knitr::opts_chunk$set(echo = TRUE)
library(tidyverse)
library(lubridate)
library(leaflet)
library(DT)
library(genepop)
library(abind)
bbind <- function(...) { abind(..., along = 3) }
Sys.setenv(RGL_USE_NULL = TRUE)
library(rgl)
.username <- "krshedd"
.password <- ""
source("~/../R/Functions.GCL.R")

Introduction

Purpose

This is a quick baseline update to Andy Barclay’s 2015 Kodiak chum baseline. This baseline update includes 3 new collections sampled by ADF&G staff (Birch Foster) in 2017:

  1. CMBARL17 - Barling Bay Creek - 9/1/2017
  2. CMKIAV17 - Kiavak Portage - 9/1/2017
  3. CMNATA17 - Natalia Bay Creek - 9/1/2017

Background

Andy’s work in late 2015 was done to assess population genetic structure of chum salmon in SE Kodiak, specifically in the Three Saints Bay area. Kodiak Regional Aquaculture Association (KRAA) wanted to establish a new hatchery in Old Harbor to make early-run chum salmon for a remote release site in Three Saints Bay. KRAA intended to use the Sturgeon broodstock, that they already use for their Kitoi Bay facility. ADF&G regional staff indicated that there are known early-run chum stocks in the Three Saints Bay area, which would present a genetic risk to using Sturgeon River broodstock in the area (similar run timing, but potentially genetically different). Regional staff indicated that Barling Bay Creek in particular had early-run chum salmon. Thus, regional staff collected temporal samples throughout the season from Barling Bay Creek and other nearby systems to get a better understanding of population genetic structure in SE Kodiak to determine whether early-run Barling Bay Creek chum were sufficiently distinct from Sturgeon River chum to be an unaccpetable genetic risk. Ultimately, Andy’s work did show that Barling Bay Creek has significant temporal genetic structure throughout the season (July vs. August vs. September). These results resulted in a memo with a department recommendation to use local broodstock (early-run Barling Bay Creek) rather than Sturgeon River broodstock from Kitoi Bay for the Three Saints Bay project.

This 2018 baseline update will incorporate three additional collections made by ADF&G staff. The results from this baseline update are not going to change the decision regarding use of local broodsource, they are intended to provide some additional pre-hatchery baseline.

Outline

This R Notebook will perform the following tasks:

  • Read in genotype data
    • Create LocusControl
    • Read in all project genotypes
  • Map of all baseline collections
  • Pooling Barling 2015
    • Split CMBARLR15 into early, middle, and late collections (as in the 2015 baseline)
  • Determine FailureRate
  • Data QA
    • Removing fish missing >= 20% of genotypes
    • Remove within collection duplicates
    • Save final, post-QA genotypes
  • Check HWE - collections
  • Pooling temporal collections
  • Check HWE - populations
  • Map of all baseline populations
  • Explore genetic structure
    • Generate allele frequency plots
    • Fst tree
    • MDS using Fst

Read in genotype data

Need to create LocusControl for the markers we are using and then read in all the genotype data for the same collections that Andy analyzed in 2015 + the three new collections from 2017 (the update).

Markerset

This analysis is using the 96 SNPs from WASSIP.

CreateLocusControl.GCL(markersuite = "ChumGolden2011_96SNPs", username = .username, password = .password)
[1] "LocusControl created for markersuite='ChumGolden2011_96SNPs'"
loci96 <- LocusControl$locusnames
dir.create("../2018/Objects")
save_objects(c("LocusControl", "loci96"), "../2018/Objects")

Collections

We want to include the same 86 collections used by Andy in his 2015 baseline + the 3 new collections from 2017.

(collections_89 <- read_csv("../2018/collections89.csv") %>% 
  pull("silly"))
Parsed with column specification:
cols(
  silly = col_character()
)
 [1] "CHBAL92UW"    "CHLIJ92UW"    "CMLIJ09UW"    "CMBEL92UW"    "CMCAN09UW"    "CMCAN92UW"    "CMCHI09UW"    "CMCHI96UW"   
 [9] "CMCOL96UW"    "CMDEL96UW"    "CMFOST09UW"   "CMRUB96UW"    "CMRUS09UW"    "CMRUS92UW"    "CMRUS93UW"    "CMSANC09UW"  
[17] "CMSANC96UW"   "CMSMOKH10"    "CMSTE09UW"    "CMSTE92UW"    "CMSTEPR09UW"  "CMWESM93UW"   "CMVOL09UW"    "CMVOL92UW"   
[25] "CMVOL96UW"    "CMZAC92UW"    "CMWESN93UW"   "CMAMBM09UW"   "CMCHIGK09UW"  "CMWESI93UW"   "CMIVAN09UW"   "CMWESL93UW"  
[33] "CMWESK93UW"   "CMKUJUNF09UW" "CMNAKIL08UW"  "CMNECR08UW"   "CMOCEB09UW"   "CMPORTC08UW"  "CMWESJ93UW"   "CMRUDY10"    
[41] "CMWESE93UW"   "CMWESD93UW"   "CMBEARBC09UW" "CMWESH93UW"   "CMBIGRI09UW"  "CMDRYBR09UW"  "CMWESF93UW"   "CMKIAL09UW"  
[49] "CMPASS09UW"   "CMWESG93UW"   "CHAME92UW"    "CHDOG92UW"    "CHKIZ92UW"    "CMKIZH09UW"   "CHUGA92UW"    "CMUGAN09UW"  
[57] "CMBARL09UW"   "CMBARLR15"    "CMBSU92UW"    "CMBSUK09UW"   "CMCOXC09UW"   "CMDEAD09UW"   "CMDOGSC10"    "CMEAGLH09UW" 
[65] "CMWESP93UW"   "CMGULLC09UW"  "CMKARL09UW"   "CMWESA93UW"   "CMKITB09UW"   "CMPAUL15"     "CMMIDWAY15"   "CMHIDDB15"   
[73] "CMKAIUG15"    "CMOLDS10"     "CMPORTNE09UW" "CMROUGH09UW"  "CMRUSSI07UW"  "CMRUSSI09UW"  "CMSITKI09UW"  "CMSPIRU09UW" 
[81] "CMSTU08UW"    "CMSTU09UW"    "CMSTU92"      "CMWKIL08UW"   "CMWKIL09UW"   "CMZACR09UW"   "CMBARL17"     "CMKIAV17"    
[89] "CMNATA17"    
save_objects("collections_89", "../2018/Objects/")

Read in genotype data from LOKI.

LOKI2R.GCL(sillyvec = collections_89, username = .username, password = .password)
CHBAL92UW.gcl created 1 of 89 completed.
CHLIJ92UW.gcl created 2 of 89 completed.
CMLIJ09UW.gcl created 3 of 89 completed.
CMBEL92UW.gcl created 4 of 89 completed.
CMCAN09UW.gcl created 5 of 89 completed.
CMCAN92UW.gcl created 6 of 89 completed.
CMCHI09UW.gcl created 7 of 89 completed.
CMCHI96UW.gcl created 8 of 89 completed.
CMCOL96UW.gcl created 9 of 89 completed.
CMDEL96UW.gcl created 10 of 89 completed.
CMFOST09UW.gcl created 11 of 89 completed.
CMRUB96UW.gcl created 12 of 89 completed.
CMRUS09UW.gcl created 13 of 89 completed.
CMRUS92UW.gcl created 14 of 89 completed.
CMRUS93UW.gcl created 15 of 89 completed.
CMSANC09UW.gcl created 16 of 89 completed.
CMSANC96UW.gcl created 17 of 89 completed.
CMSMOKH10.gcl created 18 of 89 completed.
CMSTE09UW.gcl created 19 of 89 completed.
CMSTE92UW.gcl created 20 of 89 completed.
CMSTEPR09UW.gcl created 21 of 89 completed.
CMWESM93UW.gcl created 22 of 89 completed.
CMVOL09UW.gcl created 23 of 89 completed.
CMVOL92UW.gcl created 24 of 89 completed.
CMVOL96UW.gcl created 25 of 89 completed.
CMZAC92UW.gcl created 26 of 89 completed.
CMWESN93UW.gcl created 27 of 89 completed.
CMAMBM09UW.gcl created 28 of 89 completed.
CMCHIGK09UW.gcl created 29 of 89 completed.
CMWESI93UW.gcl created 30 of 89 completed.
CMIVAN09UW.gcl created 31 of 89 completed.
CMWESL93UW.gcl created 32 of 89 completed.
CMWESK93UW.gcl created 33 of 89 completed.
CMKUJUNF09UW.gcl created 34 of 89 completed.
CMNAKIL08UW.gcl created 35 of 89 completed.
CMNECR08UW.gcl created 36 of 89 completed.
CMOCEB09UW.gcl created 37 of 89 completed.
CMPORTC08UW.gcl created 38 of 89 completed.
CMWESJ93UW.gcl created 39 of 89 completed.
CMRUDY10.gcl created 40 of 89 completed.
CMWESE93UW.gcl created 41 of 89 completed.
CMWESD93UW.gcl created 42 of 89 completed.
CMBEARBC09UW.gcl created 43 of 89 completed.
CMWESH93UW.gcl created 44 of 89 completed.
CMBIGRI09UW.gcl created 45 of 89 completed.
CMDRYBR09UW.gcl created 46 of 89 completed.
CMWESF93UW.gcl created 47 of 89 completed.
CMKIAL09UW.gcl created 48 of 89 completed.
CMPASS09UW.gcl created 49 of 89 completed.
CMWESG93UW.gcl created 50 of 89 completed.
CHAME92UW.gcl created 51 of 89 completed.
CHDOG92UW.gcl created 52 of 89 completed.
CHKIZ92UW.gcl created 53 of 89 completed.
CMKIZH09UW.gcl created 54 of 89 completed.
CHUGA92UW.gcl created 55 of 89 completed.
CMUGAN09UW.gcl created 56 of 89 completed.
CMBARL09UW.gcl created 57 of 89 completed.
CMBARLR15.gcl created 58 of 89 completed.
CMBSU92UW.gcl created 59 of 89 completed.
CMBSUK09UW.gcl created 60 of 89 completed.
CMCOXC09UW.gcl created 61 of 89 completed.
CMDEAD09UW.gcl created 62 of 89 completed.
CMDOGSC10.gcl created 63 of 89 completed.
CMEAGLH09UW.gcl created 64 of 89 completed.
CMWESP93UW.gcl created 65 of 89 completed.
CMGULLC09UW.gcl created 66 of 89 completed.
CMKARL09UW.gcl created 67 of 89 completed.
CMWESA93UW.gcl created 68 of 89 completed.
CMKITB09UW.gcl created 69 of 89 completed.
CMPAUL15.gcl created 70 of 89 completed.
CMMIDWAY15.gcl created 71 of 89 completed.
CMHIDDB15.gcl created 72 of 89 completed.
CMKAIUG15.gcl created 73 of 89 completed.
CMOLDS10.gcl created 74 of 89 completed.
CMPORTNE09UW.gcl created 75 of 89 completed.
CMROUGH09UW.gcl created 76 of 89 completed.
CMRUSSI07UW.gcl created 77 of 89 completed.
CMRUSSI09UW.gcl created 78 of 89 completed.
CMSITKI09UW.gcl created 79 of 89 completed.
CMSPIRU09UW.gcl created 80 of 89 completed.
CMSTU08UW.gcl created 81 of 89 completed.
CMSTU09UW.gcl created 82 of 89 completed.
CMSTU92.gcl created 83 of 89 completed.
CMWKIL08UW.gcl created 84 of 89 completed.
CMWKIL09UW.gcl created 85 of 89 completed.
CMZACR09UW.gcl created 86 of 89 completed.
CMBARL17.gcl created 87 of 89 completed.
CMKIAV17.gcl created 88 of 89 completed.
CMNATA17.gcl created 89 of 89 completed.
Time difference of 2.289525 mins
Time difference of 2.289525 mins
rm(.username, .password)
dir.create("../2018/Genotypes")
dir.create("../2018/Genotypes/original")
save_sillys(collections_89, "../2018/Genotypes/original")

Map of all baseline collections

Pull the latitude/longitude data for collections_89 from OceanAK, need to remove “UW” from all sillys for filtering to get the report.

writeClipboard(paste(str_replace(collections_89, "UW", ""), collapse = ";"))
dir.create("../2018/OceanAK")

Create a map of the baseline collections

read_csv("../2018/OceanAK/collections_89_Just the Lat_Longs.csv") %>% 
  leaflet(width = "100%") %>% 
  addTiles() %>% 
  addMarkers(~ Longitude, ~ Latitude, label = ~ `Silly Code`, clusterOptions = markerClusterOptions())
Parsed with column specification:
cols(
  `Collection ID` = col_integer(),
  `Silly Code` = col_character(),
  Latitude = col_double(),
  Longitude = col_double(),
  `Common Name` = col_character()
)

Create an awesome map of the baseline collections

collections_89_info <- read_csv("../2018/OceanAK/collections_89_Collection Info_mod.csv") 
Parsed with column specification:
cols(
  `Silly Code` = col_character(),
  Region = col_character(),
  Quadrant = col_character(),
  Location = col_character(),
  Latitude = col_double(),
  Longitude = col_double(),
  `Collection Date` = col_character(),
  `Date Received` = col_character()
)
collections_89_info %>% 
  count(Quadrant)
collections_89_info <- collections_89_info %>% 
  mutate(color = case_when(Quadrant == "Peninsula - South" ~ "red",
                           Quadrant == "Chignik" ~ "orange",
                           Quadrant == "Kodiak Mainland" ~ "blue",
                           Quadrant == "Kodiak/Afognak Islands" ~ "purple"))
icons <- awesomeIcons(icon = 'ios-close', iconColor = 'black', library = 'ion', markerColor = collections_89_info$color)
collections_89_info %>% 
  leaflet(width = "100%") %>% 
  addTiles() %>% 
  addAwesomeMarkers(~ Longitude, ~ Latitude, icon = icons, label = ~ `Silly Code`)

Pooling Barling 2015

We need to split CMBARLR15 into early, middle, and late collections (as in the 2015 baseline), as this silly represents 3 distinct collections.

table(CMBARLR15.gcl$attributes$CAPTURE_DATE)

2015-07-09 2015-08-03 2015-09-11 
       104        104         88 

Use AttributesToIDs.GCL to split by date and pool into new silly’s.

# early
CMBARLR15_early_ids <- AttributesToIDs.GCL(silly = "CMBARLR15", attribute = "CAPTURE_DATE", matching = "2015-07-09")
PoolCollections.GCL(collections = "CMBARLR15", loci = loci96, IDs = list(CMBARLR15 = CMBARLR15_early_ids), newname = "CMBARLR15E")
NULL
# middle
CMBARLR15_middle_ids <- AttributesToIDs.GCL(silly = "CMBARLR15", attribute = "CAPTURE_DATE", matching = "2015-08-03")
PoolCollections.GCL(collections = "CMBARLR15", loci = loci96, IDs = list(CMBARLR15 = CMBARLR15_middle_ids), newname = "CMBARLR15M")
NULL
# late
CMBARLR15_late_ids <- AttributesToIDs.GCL(silly = "CMBARLR15", attribute = "CAPTURE_DATE", matching = "2015-09-11")
PoolCollections.GCL(collections = "CMBARLR15", loci = loci96, IDs = list(CMBARLR15 = CMBARLR15_late_ids), newname = "CMBARLR15L")
NULL
save_sillys(c("CMBARLR15E", "CMBARLR15M", "CMBARLR15L"), "../2018/Genotypes/original/")

Now create a new sillyvec with the three temporal 2015 Barling collections split out and the original CMBARLR15 removed. Planning to sort for ease of use.

(collections_91 <- sort(c(collections_89[collections_89 != "CMBARLR15"], "CMBARLR15E", "CMBARLR15M", "CMBARLR15L")))
 [1] "CHAME92UW"    "CHBAL92UW"    "CHDOG92UW"    "CHKIZ92UW"    "CHLIJ92UW"    "CHUGA92UW"    "CMAMBM09UW"   "CMBARL09UW"  
 [9] "CMBARL17"     "CMBARLR15E"   "CMBARLR15L"   "CMBARLR15M"   "CMBEARBC09UW" "CMBEL92UW"    "CMBIGRI09UW"  "CMBSU92UW"   
[17] "CMBSUK09UW"   "CMCAN09UW"    "CMCAN92UW"    "CMCHI09UW"    "CMCHI96UW"    "CMCHIGK09UW"  "CMCOL96UW"    "CMCOXC09UW"  
[25] "CMDEAD09UW"   "CMDEL96UW"    "CMDOGSC10"    "CMDRYBR09UW"  "CMEAGLH09UW"  "CMFOST09UW"   "CMGULLC09UW"  "CMHIDDB15"   
[33] "CMIVAN09UW"   "CMKAIUG15"    "CMKARL09UW"   "CMKIAL09UW"   "CMKIAV17"     "CMKITB09UW"   "CMKIZH09UW"   "CMKUJUNF09UW"
[41] "CMLIJ09UW"    "CMMIDWAY15"   "CMNAKIL08UW"  "CMNATA17"     "CMNECR08UW"   "CMOCEB09UW"   "CMOLDS10"     "CMPASS09UW"  
[49] "CMPAUL15"     "CMPORTC08UW"  "CMPORTNE09UW" "CMROUGH09UW"  "CMRUB96UW"    "CMRUDY10"     "CMRUS09UW"    "CMRUS92UW"   
[57] "CMRUS93UW"    "CMRUSSI07UW"  "CMRUSSI09UW"  "CMSANC09UW"   "CMSANC96UW"   "CMSITKI09UW"  "CMSMOKH10"    "CMSPIRU09UW" 
[65] "CMSTE09UW"    "CMSTE92UW"    "CMSTEPR09UW"  "CMSTU08UW"    "CMSTU09UW"    "CMSTU92"      "CMUGAN09UW"   "CMVOL09UW"   
[73] "CMVOL92UW"    "CMVOL96UW"    "CMWESA93UW"   "CMWESD93UW"   "CMWESE93UW"   "CMWESF93UW"   "CMWESG93UW"   "CMWESH93UW"  
[81] "CMWESI93UW"   "CMWESJ93UW"   "CMWESK93UW"   "CMWESL93UW"   "CMWESM93UW"   "CMWESN93UW"   "CMWESP93UW"   "CMWKIL08UW"  
[89] "CMWKIL09UW"   "CMZAC92UW"    "CMZACR09UW"  
save_objects("collections_91", "../2018/Objects/")

Save sillys post split.

dir.create("../2018/Genotypes/original_split")
save_sillys(collections_91, "../2018/Genotypes/original_split")

Determine FailureRate

project <- "westward_chum_baseline"
loci <- loci96
(failure_rate <- FailureRate.GCL(sillyvec = collections_91))
$`silly_failure_rate`

$locus_failure_rate

$plate_failure_rate

$overall_failure_rate

$plot_silly_failure_rate

$plot_plate_failure_rate

failure_rate_noplots <- failure_rate[1:4]
save_objects("failure_rate_noplots", "../2018/Objects/")

Also calculate sample size by locus and save.

(sample_size_by_locus <- SampSizeByLocus.GCL(sillyvec = collections_91, loci = loci96) %>% 
  as_tibble(rownames = "silly"))
dir.create("../2018/Tables")
write_csv(sample_size_by_locus, "../2018/Tables/sample_size_by_locus.csv")

Data QA

Perform standard data QA processes to filter out untrustworth genotypes.

sample_size_qa <- tibble(silly = collections_91) %>% 
  mutate(genotyped = sapply(silly, function(x) get(paste0(x, ".gcl"))$n))

Missing

Remove individuals missing >=20% of genotypes (i.e. the 80% rule).

miss_loci <- RemoveIndMissLoci.GCL(sillyvec = collections_91, proportion = 0.8)
save_objects("miss_loci", "../2018/Objects/")
# show individuals removed
miss_loci[miss_loci != "None"]
$`CHBAL92UW`
[1] "10" "22"

$CHKIZ92UW
[1] "48" "54" "64" "81"

$CHUGA92UW
[1] "60"

$CMBARL09UW
[1] "92" "95"

$CMBARL17
[1] "63"

$CMBARLR15E
[1] "50" "56" "59" "61" "62" "77"

$CMBARLR15L
 [1] "3"  "16" "17" "19" "20" "42" "46" "61" "76" "85"

$CMBARLR15M
[1] "26" "28"

$CMBEARBC09UW
[1] "66" "84"

$CMCAN09UW
[1] "58" "64" "71"

$CMCAN92UW
[1] "93"

$CMCHI09UW
[1] "16" "52" "95"

$CMCHI96UW
[1] "19" "29" "54"

$CMCHIGK09UW
[1] "38"

$CMCOXC09UW
[1] "39"

$CMFOST09UW
[1] "25" "43" "72" "80" "86" "94"

$CMGULLC09UW
[1] "86"

$CMKAIUG15
[1] "66" "80"

$CMKARL09UW
[1] "15" "25" "45" "58" "60" "66" "91"

$CMKITB09UW
  [1] "96"  "97"  "98"  "99"  "100" "101" "102" "103" "104" "105" "106" "107" "108" "109" "110" "111" "112" "113" "114" "115"
 [21] "116" "117" "118" "119" "120" "121" "122" "123" "124" "125" "126" "127" "128" "129" "130" "131" "132" "133" "134" "135"
 [41] "136" "137" "138" "139" "140" "141" "142" "143" "144" "145" "146" "147" "148" "149" "150" "151" "152" "153" "154" "155"
 [61] "156" "157" "158" "159" "160" "161" "162" "163" "164" "165" "166" "167" "168" "169" "170" "171" "172" "173" "174" "175"
 [81] "176" "177" "178" "179" "180" "181" "182" "183" "184" "185" "186" "187" "188" "189" "190" "191" "192" "193" "194" "195"
[101] "196" "197" "198" "199" "200" "201" "202"

$CMKIZH09UW
[1] "10" "14" "31" "55"

$CMKUJUNF09UW
[1] "14" "15"

$CMLIJ09UW
[1] "8"  "33" "34"

$CMMIDWAY15
[1] "1"

$CMNAKIL08UW
 [1] "96"  "97"  "98"  "99"  "100" "101" "102" "103" "104" "105" "106" "107"

$CMNECR08UW
 [1] "13"  "96"  "97"  "98"  "99"  "100" "101" "102" "103" "104" "105" "106" "107" "108" "109" "110" "111" "112"

$CMPASS09UW
[1] "41"

$CMPAUL15
[1] "16"

$CMPORTNE09UW
[1] "8"

$CMROUGH09UW
 [1] "1"  "5"  "13" "25" "30" "33" "35" "44" "46" "51" "64" "70" "74" "78" "86" "87" "89" "93"

$CMRUB96UW
[1] "31" "71" "83"

$CMRUDY10
[1] "61" "92"

$CMRUS09UW
[1] "48"

$CMRUS93UW
[1] "74" "79"

$CMRUSSI07UW
[1] "48"

$CMRUSSI09UW
[1] "50" "63" "69"

$CMSANC96UW
[1] "6"  "89"

$CMSITKI09UW
[1] "87" "95"

$CMSPIRU09UW
[1] "30" "38" "42" "44" "58" "93"

$CMSTE09UW
[1] "69"

$CMSTEPR09UW
[1] "95"

$CMSTU09UW
 [1] "64"  "105" "106" "107" "108" "109" "110" "111" "112" "113" "114" "115" "116" "117" "118" "119" "120" "121" "122" "123"
[21] "124" "125"

$CMSTU92
 [1] "1"  "2"  "3"  "4"  "5"  "6"  "7"  "8"  "9"  "10" "11" "12" "13" "14" "15" "16" "17" "18" "19" "20" "21" "22" "23" "24"
[25] "25" "26" "27" "28" "29" "30" "31" "32" "33" "34" "35" "36" "37" "38" "39" "40" "41" "42" "43" "44" "45" "46" "47" "48"
[49] "49" "50" "51" "52" "53" "54" "55" "56" "57" "58" "59" "60" "61" "62" "63" "64" "65" "66" "67" "68" "69" "70" "71"

$CMUGAN09UW
 [1] "11" "16" "30" "43" "45" "49" "51" "63" "76" "86" "87" "88" "91" "95"

$CMVOL96UW
[1] "27"

$CMWESA93UW
[1] "6"

$CMWESE93UW
[1] "6"

$CMWESF93UW
[1] "44" "45" "46" "47" "48" "68" "86"

$CMWESG93UW
[1] "4"

$CMWESH93UW
[1] "34" "73"

$CMWESI93UW
[1] "55"

$CMWESK93UW
[1] "30"

$CMWESL93UW
[1] "32"

$CMWESN93UW
[1] "23" "36"

$CMWESP93UW
[1] "17" "37" "46"

$CMWKIL09UW
[1] "34" "42" "59" "70"

$CMZAC92UW
[1] "68" "71" "74"

$CMZACR09UW
[1] "37"
sample_size_qa <- sample_size_qa %>% 
  mutate(missing = genotyped - sapply(silly, function(x) get(paste0(x, ".gcl"))$n))

Duplicate

Remove duplicate individuals within the same collection. Typically we specify duplicates as a pair of individuals that share >=95% of genotypes. Once a pair of duplicates is identified, we keep the individual with the most genotypes and remove the other.

duplicate_check_95 <- CheckDupWithinSilly.GCL(sillyvec = collections_91, loci = loci96, quantile = NULL, minproportion = 0.95)
duplicate_summary <- sapply(collections_91, function(x) duplicate_check_95[[x]]$report, simplify = FALSE)
duplicate_remove <- RemoveDups.GCL(duplicate_check_95)
save_objects(c("duplicate_summary", "duplicate_remove"), "../2018/Objects/")
# show individuals removed
duplicate_remove[duplicate_remove != "Nothing Removed"]
$`CMBARLR15E`
[1] "87"  "21"  "100" "13" 

$CMBEARBC09UW
[1] "38"

$CMBSUK09UW
[1] "36"

$CMCHI09UW
[1] "19" "34" "44"

$CMCHI96UW
[1] "7"

$CMCHIGK09UW
[1] "48"

$CMCOXC09UW
[1] "23"

$CMEAGLH09UW
[1] "30"

$CMIVAN09UW
[1] "5"

$CMKARL09UW
[1] "80"

$CMKIAL09UW
[1] "11"

$CMKIAV17
[1] "30"

$CMKIZH09UW
[1] "58"

$CMOLDS10
[1] "38" "80"

$CMRUSSI07UW
[1] "14"

$CMSANC96UW
[1] "49" "36"

$CMSTE09UW
[1] "32"

$CMWESN93UW
[1] "10"

$CMZAC92UW
[1] "13"
sample_size_qa <- sample_size_qa %>% 
  mutate(duplicate = genotyped - missing - sapply(silly, function(x) get(paste0(x, ".gcl"))$n))

Final

How many fish did we end up with in our final baseline? Save final genotypes.

(sample_size_qa <- sample_size_qa %>% 
  mutate(final = sapply(silly, function(x) get(paste0(x, ".gcl"))$n)))
write_csv(sample_size_qa, "../2018/Tables/sample_size_qa.csv")
dir.create("../2018/Genotypes/original_split_postQA/")
save_sillys(collections_91, "../2018/Genotypes/original_split_postQA/")

What is smallest collection?

Whoa, we should totally junk some of these collections given their low sample size (or complete lack of fish!). We’ll keep anything with at least 40 fish.

(collections_88 <- sample_size_qa %>% 
   filter(final > 40) %>% 
   pull("silly"))
 [1] "CHAME92UW"    "CHBAL92UW"    "CHDOG92UW"    "CHKIZ92UW"    "CHLIJ92UW"    "CHUGA92UW"    "CMAMBM09UW"   "CMBARL09UW"  
 [9] "CMBARL17"     "CMBARLR15E"   "CMBARLR15L"   "CMBARLR15M"   "CMBEARBC09UW" "CMBEL92UW"    "CMBIGRI09UW"  "CMBSU92UW"   
[17] "CMBSUK09UW"   "CMCAN09UW"    "CMCAN92UW"    "CMCHI09UW"    "CMCHI96UW"    "CMCHIGK09UW"  "CMCOL96UW"    "CMCOXC09UW"  
[25] "CMDEAD09UW"   "CMDEL96UW"    "CMDOGSC10"    "CMDRYBR09UW"  "CMEAGLH09UW"  "CMFOST09UW"   "CMGULLC09UW"  "CMHIDDB15"   
[33] "CMIVAN09UW"   "CMKAIUG15"    "CMKARL09UW"   "CMKIAL09UW"   "CMKIAV17"     "CMKITB09UW"   "CMKIZH09UW"   "CMKUJUNF09UW"
[41] "CMLIJ09UW"    "CMMIDWAY15"   "CMNAKIL08UW"  "CMNATA17"     "CMNECR08UW"   "CMOCEB09UW"   "CMOLDS10"     "CMPASS09UW"  
[49] "CMPAUL15"     "CMPORTC08UW"  "CMPORTNE09UW" "CMROUGH09UW"  "CMRUB96UW"    "CMRUDY10"     "CMRUS09UW"    "CMRUS92UW"   
[57] "CMRUS93UW"    "CMRUSSI07UW"  "CMRUSSI09UW"  "CMSANC09UW"   "CMSANC96UW"   "CMSITKI09UW"  "CMSMOKH10"    "CMSPIRU09UW" 
[65] "CMSTE09UW"    "CMSTE92UW"    "CMSTEPR09UW"  "CMSTU09UW"    "CMUGAN09UW"   "CMVOL09UW"    "CMVOL92UW"    "CMVOL96UW"   
[73] "CMWESA93UW"   "CMWESD93UW"   "CMWESE93UW"   "CMWESF93UW"   "CMWESG93UW"   "CMWESH93UW"   "CMWESI93UW"   "CMWESJ93UW"  
[81] "CMWESK93UW"   "CMWESL93UW"   "CMWESM93UW"   "CMWESN93UW"   "CMWESP93UW"   "CMWKIL09UW"   "CMZAC92UW"    "CMZACR09UW"  
save_objects("collections_88", "../2018/Objects/")

Check HWE - collections

Write out a Genepop file to check HWE within collections.

dir.create("../2018/Genepop")
gcl2Genepop.GCL(sillyvec = collections_88, loci = loci96, path = "../2018/Genepop/collections_88.gen", VialNums = TRUE)
NULL

Calculate HWE using the genepop package link.

test_HW(inputFile = "../2018/Genepop/collections_88.gen", outputFile = "../2018/Genepop/collections_88.P.txt")
Dangerous input file name extension:
   the genepop code expects either extension '.txt' or no extension.
Results are stored in file ../2018/Genepop/collections_88.P.txt 

Summary table

Read in results and save summary HWE p-values.

hwe_collections_88 <- ReadGenepopHWE.GCL(file = "../2018/Genepop/collections_88.txt.P", sillyvec = collections_88)
Read 18222 items
All p-values are pulled directly from the Genepop *.P file if calculated via Exact test.
If calculated via MCMC then over all loci/pops are derived in this function, correcting p = 0 for the number of batches * iterations!
NA in 'smmry' dataframe means that locus in either 1) monomorphic (or very low MAF) or 2) not diploid (haploid mtSNP).
Haploid loci are not included in the 'HWdata' data.frame.NULL
(hwe_summary_collections_88 <- hwe_collections_88$SummaryPValues %>% 
  as_tibble(rownames = "locus"))
write_csv(x = hwe_summary_collections_88, "../2018/Tables/hwe_summary_collections_88.csv")

Collections out of HWP

What do overall-loci p-values look like for collections?

All look pretty good with the potential exception of CMBARLR15L.

Loci out of HWP

What do overall-loci p-values look like for loci?

There are a couple of loci that are suspect.

HWP plots

Per Waples 2014, we will plot a histogram of HWP p-values to look for collections/loci that do not conform to HWP. We will limit our search to the specific collection and loci that were suspicious.

Collection

Plot p-values per locus for CMBARLR15L

hwe_summary_collections_88 %>% 
  gather(silly, p, -locus) %>%
  filter(silly == "CMBARLR15L") %>% 
  filter(locus != "Overall Loci") %>% 
  ggplot(aes(p)) + 
  geom_histogram(binwidth = 0.05) +
  geom_hline(yintercept = 5, colour = "red") +
  ggtitle("HWP p-values by locus for CMBARLR15L")

Looks fine, no major cause for concern, now on to plotting for loci.

Loci

Plot p-values per collection for loci with overall pops p-value < 0.2.

# filter for loci with overall pops < 0.2
hwe_loci_plot <- hwe_summary_collections_88 %>% 
  gather(silly, p, -locus) %>%
  filter(silly == "Overall Pops" & p < 0.2) %>% 
  pull(locus)
# plot
hwe_summary_collections_88 %>% 
  gather(silly, p, -locus) %>%
  filter(locus %in% hwe_loci_plot) %>% 
  filter(silly != "Overall Pops") %>%
  ggplot(aes(p)) + 
  geom_histogram(binwidth = 0.05) +
  geom_hline(yintercept = length(collections_88) / 20, colour = "red") +
  ggtitle("HWP p-values by collection") +
  facet_grid( ~ locus)

Oke_U2041-84 and Oke_U506-110 are a bit suspect, but we’ll let them go since their overall p-values were > 0.05.

Takeaway

All collections and loci were retained.

Pooling temporal collections

Now I’ll follow Andy’s pooling of temporal collections in to populations.

Non-Barling

Andy’s

Create a list for pooling (excluding Barling). Note some are different than Andy’s (i.e. Stepovak)

temporal_pooling <- list("Amber Bay" = c("CMWESN93UW", "CMAMBM09UW"),
                         "Balboa Bay" = c("CHBAL92UW", "CMFOST09UW"),
                         "Hallo Bay" = c("CMWESH93UW", "CMBIGRI09UW"),
                         "Bear Bay" = c("CMWESD93UW", "CMBEARBC09UW"),
                         "Big Sukhoi" = c("CMBSU92UW", "CMBSUK09UW"),
                         "Canoe Bay" = c("CMCAN92UW", "CMCAN09UW"),
                         "Chichagof Bay" = c("CMCHI96UW", "CMCHI09UW"),
                         "Chigniagak Bay" = c("CMWESI93UW", "CMCHIGK09UW"),
                         "Gull Cape Creek" = c("CMWESP93UW", "CMGULLC09UW"),
                         "Ivanof River" = c("CMWESL93UW", "CMIVAN09UW"),
                         "Kialagvik Creek" = c("CMWESF93UW", "CMKIAL09UW"),
                         "Kitoi Bay" = c("CMWESA93UW", "CMKITB09UW"),
                         "Kizhuyak River" = c("CHKIZ92UW", "CMKIZH09UW"),
                         "Kujulik Bay" = c("CMWESK93UW", "CMKUJUNF09UW"),
                         "Little John Lagoon" = c("CHLIJ92UW", "CMLIJ09UW"),
                         "Portage Creek" = c("CMWESJ93UW", "CMPORTC08UW"),
                         "Russell Creek" = c("CMRUS92UW", "CMRUS93UW", "CMRUS09UW"),
                         "Russian River" = c("CMRUSSI07UW", "CMRUSSI09UW"),
                         "Sandy Cove" = c("CMSANC96UW", "CMSANC09UW"),
                         "Stepovak Bay" = c("CMSTE92UW", "CMWESM93UW", "CMSTE09UW"),
                         "Uganik River" = c("CHUGA92UW", "CMUGAN09UW"),
                         "Volcano Bay" = c("CMVOL92UW", "CMVOL96UW", "CMVOL09UW")
)
save_objects("temporal_pooling", "../2018/Objects/")
# verify that all sillys are in collections_88
setdiff(unlist(temporal_pooling), collections_88)
character(0)

Now that we have our list of putative populations to pool, let’s see how they do in Fisher’s test.

collections_88_allele_freq <- FreqPop.GCL(sillyvec = collections_88, loci = loci96)
temporal_pooling_results <- FishersTest.GCL(freq = collections_88_allele_freq, loci = loci96, tests = temporal_pooling)
save_objects(c("collections_88_allele_freq", "temporal_pooling_results"), "../2018/Objects/")
# overall loci p-values
temporal_pooling_results$OverallResults %>% 
  as_tibble(rownames = "pop") %>% 
  arrange(overall)

WASSIP

I went and double checked the WASSIP chum baseline SP 12-26, Table 2. Should have done this first.

  • The 1992 and 1996 Volcano Bay collections got dropped (-CMVOL92UW, -CMVOL96UW)
  • Pool Stepovak Bay 1992 and 2009, keep Stepovak River 2009 separate, drop 1993 Stepovak River (-CMWESM93UW)
  • Drop Amber Bay 1993 (-CMWESN93UW)
  • Drop Hallo Bay 1993 (-CMWESH93UW)
temporal_pooling_WASSIP <- list("Balboa Bay" = c("CHBAL92UW", "CMFOST09UW"),
                                "Bear Bay" = c("CMWESD93UW", "CMBEARBC09UW"),
                                "Big Sukhoi" = c("CMBSU92UW", "CMBSUK09UW"),
                                "Canoe Bay" = c("CMCAN92UW", "CMCAN09UW"),
                                "Chichagof Bay" = c("CMCHI96UW", "CMCHI09UW"),
                                "Chigniagak Bay" = c("CMWESI93UW", "CMCHIGK09UW"),
                                "Gull Cape Creek" = c("CMWESP93UW", "CMGULLC09UW"),
                                "Ivanof River" = c("CMWESL93UW", "CMIVAN09UW"),
                                "Kialagvik Creek" = c("CMWESF93UW", "CMKIAL09UW"),
                                "Kitoi Bay" = c("CMWESA93UW", "CMKITB09UW"),
                                "Kizhuyak River" = c("CHKIZ92UW", "CMKIZH09UW"),
                                "Kujulik Bay" = c("CMWESK93UW", "CMKUJUNF09UW"),
                                "Little John Lagoon" = c("CHLIJ92UW", "CMLIJ09UW"),
                                "Portage Creek" = c("CMWESJ93UW", "CMPORTC08UW"),
                                "Russell Creek" = c("CMRUS92UW", "CMRUS93UW", "CMRUS09UW"),
                                "Russian River" = c("CMRUSSI07UW", "CMRUSSI09UW"),
                                "Sandy Cove" = c("CMSANC96UW", "CMSANC09UW"),
                                "Stepovak Bay" = c("CMSTE92UW", "CMSTE09UW"),
                                "Uganik River" = c("CHUGA92UW", "CMUGAN09UW")
)
save_objects("temporal_pooling_WASSIP", "../2018/Objects/")
# verify that all sillys are in collections_88
setdiff(unlist(temporal_pooling_WASSIP), collections_88)
character(0)

Now that we have our list of WASSIP populations to pool, let’s see how they do in Fisher’s test.

temporal_pooling_WASSIP_results <- FishersTest.GCL(freq = collections_88_allele_freq, loci = loci96, tests = temporal_pooling_WASSIP)
save_objects("temporal_pooling_WASSIP_results", "../2018/Objects/")
# overall loci p-values
temporal_pooling_WASSIP_results$OverallResults %>% 
  as_tibble(rownames = "pop") %>% 
  arrange(overall)

Looks good enough to me, also coincides with WASSIP, so that is good news. Now on to check Barling.

Barling

Test all possible pairwise combinations of Barling samples

barling_pooling <- combn(x = grep(pattern = "BARL", x = collections_88, value = TRUE), m = 2, simplify = FALSE)
save_objects("temporal_pooling_WASSIP", "../2018/Objects/")
barling_pooling_results <- FishersTest.GCL(freq = collections_88_allele_freq, loci = loci96, tests = barling_pooling)
save_objects("barling_pooling_results", "../2018/Objects/")
# overall loci p-values
barling_pooling_results$OverallResults %>% 
  as_tibble(rownames = "pop") %>% 
  arrange(overall)

While it certainly does seem like we “could” pool some of the Barling collections per our WASSIP rules, I think it is best to leave them all separate for now for plotting purposes.

Final pooling

Accept all WASSIP pooling and move on.

invisible(
  lapply(temporal_pooling_WASSIP, function(pop) {
    PoolCollections.GCL(collections = pop, loci = loci96, IDs = NULL, newname = paste(pop, collapse = "."))
  } )
)

Ordered populations

Need new sillyvec with pooled populations.

collections_post_pooling <- c(
  setdiff(setdiff(collections_88, 
          unlist(temporal_pooling_WASSIP)),  # get single collections from non-WASSIP pooling
  c("CMVOL92UW", "CMVOL96UW", "CMWESM93UW", "CMWESN93UW", "CMWESH93UW")), # drop these old collections that didn't pool
  sapply(temporal_pooling_WASSIP, function(pop) {
    paste(pop, collapse = ".")  # add pooled WASSIP
  })
)
dir.create("../2018/Genotypes/original_split_postQA_postpooling/")
'..\2018\Genotypes\original_split_postQA_postpooling' already exists
save_sillys(collections_post_pooling, "../2018/Genotypes/original_split_postQA_postpooling/")
Error in save_sillys(collections_post_pooling, "../2018/Genotypes/original_split_postQA_postpooling/") : 
  These sillys:
CHAME92UW
CHDOG92UW
CMAMBM09UW
CMBARL09UW
CMBARL17
CMBARLR15E
CMBARLR15L
CMBARLR15M
CMBEL92UW
CMBIGRI09UW
CMCOL96UW
CMCOXC09UW
CMDEAD09UW
CMDEL96UW
CMDOGSC10
CMDRYBR09UW
CMEAGLH09UW
CMHIDDB15
CMKAIUG15
CMKARL09UW
CMKIAV17
CMMIDWAY15
CMNAKIL08UW
CMNATA17
CMNECR08UW
CMOCEB09UW
CMOLDS10
CMPASS09UW
CMPAUL15
CMPORTNE09UW
CMROUGH09UW
CMRUB96UW
CMRUDY10
CMSITKI09UW
CMSMOKH10
CMSPIRU09UW
CMSTEPR09UW
CMSTU09UW
CMVOL09UW
CMWESE93UW
CMWESG93UW
CMWKIL09UW
CMZAC92UW
CMZACR09UW
CHBAL92UW.CMFOST09UW
CMWESD93UW.CMBEARBC09UW
CMBSU92UW.CMBSUK09UW
CMCAN92UW.CMCAN09UW
CMCHI96UW.CMCHI09UW
CMWESI93UW.CMCHIGK09UW
CMWESP93UW.CMGULLC09UW
CMWESL93UW.CMIVAN09UW
CMWESF93UW.CMKIAL09UW
CMWESA93UW.CMKITB09UW
CHKIZ92UW.CMKIZH09UW
CMWESK93UW.CMKUJUNF09UW
CHLIJ92UW.CMLIJ09UW
CMWESJ93UW.CMPORTC08UW
CMRUS92UW.CMRUS93UW.CMRUS09UW
CMRUSSI07UW.CMRUSSI09UW
CMSANC96UW.CMSANC09UW
CMSTE92UW.CMSTE09UW
CHUGA92UW.CMUGAN09UW
are not in your workspace, hoser!!!

Now need to join up these post pooling collections (populations) with the paired OceanAK data from collections_89_info and get in geographical order.

Add new grouping variable for:
* South Peninsula * Chignik * Kodiak Mainland * Kodiak * Sturgeon/Kitoi * Barling River * 2017 Collections

populations_63_info <- tibble(pop = collections_post_pooling) %>% 
  mutate(n = sapply(collections_post_pooling, function(x) {get(paste0(x, ".gcl"))$n} )) %>%  # get final sample sizes
  mutate(pop_no_UW = str_remove_all(pop, "UW")) %>%  # remove UW extension
  mutate(pop_no_UW = dplyr::recode(pop_no_UW, !!!list("CMBARLR15E" = "CMBARLR15", "CMBARLR15M" = "CMBARLR15", "CMBARLR15L" = "CMBARLR15"))) %>%  # remove E, M, L extension for Barling 2015 for joining
  separate(pop_no_UW, c("col1", "col2", "col3"), sep = "\\.", remove = TRUE) %>%  # separate sillys to join dates
  left_join(select(collections_89_info, `Silly Code`, `Collection Date`), by = c("col1" = "Silly Code")) %>%  # get date 1
  left_join(select(collections_89_info, `Silly Code`, `Collection Date`), by = c("col2" = "Silly Code")) %>%  # get date 2
  left_join(select(collections_89_info, `Silly Code`, `Collection Date`), by = c("col3" = "Silly Code")) %>%  # get date 3
  rename("Collection Date 1" = "Collection Date.x", "Collection Date 2" = "Collection Date.y", "Collection Date 3" = "Collection Date") %>%  # rename dates
  mutate(`Collection Date 1` = str_replace(`Collection Date 1`, "1/1/1992", "1992")) %>%  # CMZAC09 has bogus date
  mutate(col = ifelse(is.na(col3), ifelse(is.na(col2), col1, col2), col3)) %>%  # get latest collection from each pop
  left_join(select(collections_89_info, `Silly Code`, Quadrant, color, Location, Latitude, Longitude), by = c("col" = "Silly Code")) %>%  # join OceanAK based on latest collection from each pop
  mutate(Group = case_when(Quadrant == "Peninsula - South" ~ "South Peninsula",
                           Quadrant == "Chignik" ~ "Chignik",
                           Quadrant == "Kodiak Mainland" ~ "Kodiak Mainland",
                           pop %in% c("CMPAUL15", "CMSTU09UW", "CMWESA93UW.CMKITB09UW") ~ "Sturgeon/Kitoi Bay",
                           pop %in% c("CMBARL09UW", "CMBARLR15E", "CMBARLR15M", "CMBARLR15L") ~ "Barling Bay",
                           pop %in% c("CMNATA17", "CMKIAV17", "CMBARL17") ~ "2017 Collections",
                           TRUE ~ "Kodiak")) %>%  # create group for groupvec
  dplyr::select(pop, Location, `Collection Date 1`, `Collection Date 2`, `Collection Date 3`, Group, Quadrant, n, Latitude, Longitude, color) %>%  # keep columns
  separate(Location, c("Location", "trash"), sep = " - ") %>%  # standardize Locations part 1
  separate(Location, c("Location", "more_trash"), sep = " \\(") %>%  # standardize Locations part 2
  dplyr::select(-trash, -more_trash) %>%  # drop bogus location info
  mutate(`Collection Date 1` = case_when(pop == "CMBARLR15M" ~ "8/3/2015",
                                         pop == "CMBARLR15L" ~ "9/11/2015",
                                         TRUE ~ `Collection Date 1`)) %>%  # fix Barling 2015 dates
  mutate(Month = month(mdy(`Collection Date 1`), label = TRUE)) %>% #  extract month
  dplyr::select(pop, Location, `Collection Date 1`, `Collection Date 2`, `Collection Date 3`, Month, Group, Quadrant, n, Latitude, Longitude, color)  # keep columns

Create a leaflet map to determine map order for populations.

populations_63_info <- populations_63_info %>% 
  mutate(color = case_when(Group == "South Peninsula" ~ "red",
                           Group == "Chignik" ~ "darkred",
                           Group == "Kodiak Mainland" ~ "orange",
                           Group == "Kodiak" ~ "green",
                           Group == "Sturgeon/Kitoi Bay" ~ "blue",
                           Group == "Barling Bay" ~ "purple",
                           Group == "2017 Collections" ~ "darkpurple"))
colors_7 <- c("red", "darkred", "orange", "blue", "green", "purple", "violet")
save_objects("colors_7", "../2018/Objects/")
icons <- awesomeIcons(icon = 'circle', iconColor = 'black', library = 'ion', markerColor = populations_63_info$color)
populations_63_info %>% 
  leaflet(width = "100%") %>% 
  addTiles() %>% 
  addAwesomeMarkers(~ Longitude, ~ Latitude, icon = icons, label = ~ pop, labelOptions = labelOptions(noHide = TRUE, direction = "auto"))

Save geography ordered population vector.

populations_63 <- read_csv("../2018/populations_63.csv")
Parsed with column specification:
cols(
  pop_no = col_integer(),
  map_no = col_integer(),
  pop = col_character()
)
populations_63_info <- populations_63_info %>% 
  left_join(populations_63, by = "pop") %>% 
  select(pop_no, map_no, pop, Location, `Collection Date 1`, `Collection Date 2`, `Collection Date 3`, Month, Group, Quadrant, n, Latitude, Longitude, color) %>% 
  arrange(pop_no)
write_csv(populations_63_info, "../2018/Tables/populations_63_info.csv")
populations_63 <- populations_63$pop
groups_7 <- unique(populations_63_info$Group)
groupvec_7 <- match(populations_63_info$Group, groups_7)
save_objects(c("populations_63", "populations_63_info", "groups_7", "groupvec_7"), "../2018/Objects/")

Final map

Make map with the correct map numbers to double check.

icons <- awesomeIcons(icon = 'egg', iconColor = 'transparent', library = 'ion', markerColor = populations_63_info$color)
populations_63_info %>% 
  leaflet(width = "100%") %>% 
  addTiles() %>% 
  addAwesomeMarkers(~ Longitude, ~ Latitude, icon = icons, label = ~ as.character(map_no), popup = ~ Location, labelOptions = labelOptions(noHide = TRUE, textOnly = TRUE, direction = "top"))

Check HWE - populations

Write out a Genepop file to check HWE within populations.

gcl2Genepop.GCL(sillyvec = populations_63, loci = loci96, path = "../2018/Genepop/populations_63.gen", VialNums = TRUE)
NULL

Calculate HWE using the genepop package link.

test_HW(inputFile = "../2018/Genepop/populations_63.gen", outputFile = "../2018/Genepop/populations_63.txt.P")
Dangerous input file name extension:
   the genepop code expects either extension '.txt' or no extension.
Results are stored in file ../2018/Genepop/populations_63.txt.P 

Summary table

Read in results and save summary HWE p-values.

hwe_populations_63 <- ReadGenepopHWE.GCL(file = "../2018/Genepop/populations_63.txt.P", sillyvec = populations_63)
Loading required package: reshape2

Attaching package: 㤼㸱reshape2㤼㸲

The following object is masked from 㤼㸱package:tidyr㤼㸲:

    smiths

Read 13322 items
All p-values are pulled directly from the Genepop *.P file if calculated via Exact test.
If calculated via MCMC then over all loci/pops are derived in this function, correcting p = 0 for the number of batches * iterations!
NA in 'smmry' dataframe means that locus in either 1) monomorphic (or very low MAF) or 2) not diploid (haploid mtSNP).
Haploid loci are not included in the 'HWdata' data.frame.NULL
(hwe_summary_populations_63 <- hwe_populations_63$SummaryPValues %>% 
  as_tibble(rownames = "locus"))
write_csv(x = hwe_summary_populations_63, "../2018/Tables/hwe_summary_populations_63.csv")

Populations out of HWP

What do overall-loci p-values look like for collections?

hwe_summary_populations_63 %>% 
  gather(silly, p, -locus) %>%
  filter(locus == "Overall Loci") %>% 
  arrange(p)

Looks pretty good, nothing major to worry aobut. On to Fst!

Combine loci

Planning to use WASSIP locus information (ADF&G SP12-26):

mito_combine <- names(which(LocusControl$ploidy == 1))
nuclear_combine <- c("Oke_U1021-102", "Oke_U1022-139")
nuclear_drop <- c("Oke_gdh1-62", "Oke_pgap-92")
CombineLoci.GCL(sillyvec = populations_63, markerset = nuclear_combine, update = TRUE, delim = ".")
NULL
CombineLoci.GCL(sillyvec = populations_63, markerset = mito_combine, update = TRUE, delim = ".")
NULL
dir.create("../2018/Genotypes/original_split_postQA_postpooling_combineloci/")
save_sillys(populations_63, "../2018/Genotypes/original_split_postQA_postpooling_combineloci/")
loci91 <- c(
  setdiff(loci96, 
          c(nuclear_drop, mito_combine, nuclear_combine)),  # drop linked markers and single combined
  paste(nuclear_combine, collapse = "."), paste(mito_combine, collapse = "."))  # add combined

Allele frequency plots

Calculate allele frequencies.

dir.create("../2018/FreqPlots")
allele_freq <- FreqFisPlot4SNPs.GCL(sillyvec = populations_63, loci = loci96, groupvec = groupvec_7, groupcol = colors_7, file = "../2018/FreqPlots/allele_freq_populations_63_loci96.pdf")

Fst

Calculate

Now that we have our final post-QA, post-pooling genotypes, time to calculate Fst between all of our populations.

dir.create("../2018/FSTAT")
Fst_tree_populations_63_loci91 <- PairwiseFstTree.GCL(sillyvec = populations_63, loci = loci91, dir = "../2018/FSTAT", nboots = 1000, ncores = 4, returnbootstrapFst = FALSE)

Heatmap of Fst

pairwise_fst <- Fst_tree_populations_63_loci91$PairwiseFst
write_csv(as_data_frame(pairwise_fst, rownames = "pop"), "../2018/Tables/pairwise_fst_populations_63.csv")
save_objects("pairwise_fst", "../2018/Objects/")
get_lower_tri <- function(mat) {
  mat[upper.tri(mat)] <- NA
  return(mat)
}
get_lower_tri(pairwise_fst) %>% 
  as_tibble(rownames = "pop1") %>%
  mutate(pop1 = factor(pop1, populations_63)) %>% 
  gather(pop2, fst, -pop1, na.rm = TRUE, factor_key = TRUE) %>% 
  ggplot(aes(x = pop1, y = pop2, fill = fst)) +
  geom_tile() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)) +
  ggtitle("Pairwise Fst - 63 Populations, 91 Loci")

MDS

All populations

Make an MDS of the Fst data for comparison to Andy’s work back in 2015.

dist = pairwise_fst
popvec = 1:63
groupsvec = 1:7
colvec = match(colors_7[groupvec_7], colors())
groups = groups_7[groupsvec]
cols = colors_7[groupsvec]
main = ""
labels = TRUE
locNames = 1:63
axes = TRUE
box = TRUE
adj = c(1.5, 1.5)
cex = 1
size = 1.3
#~~~~~~~~
names <- if(labels==F){NULL} else{if(locNames==F){popvec} else{locNames[popvec]}}
xx=dist[popvec,popvec]
x=as.vector(cmdscale(xx,k=3)[,1])
y=as.vector(cmdscale(xx,k=3)[,2])
z=-as.vector(cmdscale(xx,k=3)[,3])
plot3d(x,y,z+abs(range(z)[1]),aspect=F,col=colors()[colvec[popvec]],size=size,type='s',main=main,box=box,axes=axes,top=T,cex=1,xlab='',ylab='',zlab='',xlen=0,ylen=0,zlen=0)
plot3d(x,y,z+abs(range(z)[1]),aspect=F,col="black",size=3,type='h',box=F,axes=F,top=T,add=T,xlab='',ylab='',zlab='',xlen=0,ylen=0,zlen=0)
if(labels==T){texts3d(x,y,z+abs(range(z)[1]),adj=adj,text=names,font=1,cex=cex,add=T,top=T,axes=F,xlab='',ylab='',zlab='')}
par3d(windowRect = c(0, 0, 2000, 2000))
legend3d("topright", legend = groups, pch = 16, col = cols, inset = c(0), cex = 5)
rglwidget()

Kodiak populations

Make an MDS of the Fst data for just Kodiak populations

dist = pairwise_fst
popvec = 32:63
colvec = match(colors_7[groupvec_7], colors())
groups = groups_7[4:7]
cols = colors_7[4:7]
main = ""
labels = TRUE
locNames = 1:63
axes = TRUE
box = TRUE
adj = c(1.5, 1.5)
cex = 1
size = 1.3
#~~~~~~~~
names <- if(labels==F){NULL} else{if(locNames==F){popvec} else{locNames[popvec]}}
xx=dist[popvec,popvec]
x=as.vector(cmdscale(xx,k=3)[,1])
y=as.vector(cmdscale(xx,k=3)[,2])
z=-as.vector(cmdscale(xx,k=3)[,3])
plot3d(x,y,z+abs(range(z)[1]),aspect=F,col=colors()[colvec[popvec]],size=size,type='s',main=main,box=box,axes=axes,top=T,cex=1,xlab='',ylab='',zlab='',xlen=0,ylen=0,zlen=0)
plot3d(x,y,z+abs(range(z)[1]),aspect=F,col="black",size=3,type='h',box=F,axes=F,top=T,add=T,xlab='',ylab='',zlab='',xlen=0,ylen=0,zlen=0)
if(labels==T){texts3d(x,y,z+abs(range(z)[1]),adj=adj,text=names,font=1,cex=cex,add=T,top=T,axes=F,xlab='',ylab='',zlab='')}
par3d(windowRect = c(0, 0, 2000, 2000))
legend3d("topright", legend = groups, pch = 16, col = cols, inset = c(0), cex = 5)
rglwidget()

Kodiak populations, no outliers

Remove Sturgeon/Kito Bay populations, Karluk Lagoon, Gull Cape Lagoon, Big Sukhoi, and Sitkinak Island as outliers.

dist = pairwise_fst
popvec = populations_63_info %>% 
  mutate(pop_no = 1:63) %>% 
  filter(Quadrant == "Kodiak/Afognak Islands") %>% 
  filter(Group != "Sturgeon/Kitoi Bay") %>% 
  filter(!Location %in% c("Karluk Lagoon", "Gull Cape Lagoon", "Big Sukhoi", "Sitkinak Island")) %>% 
  pull(pop_no)
groupsvec = 5:7
colvec = match(colors_7[groupvec_7], colors())
groups = groups_7[groupsvec]
cols = colors_7[groupsvec]
main = ""
labels = TRUE
locNames = 1:63
axes = TRUE
box = TRUE
adj = c(1.5, 1.5)
cex = 1
size = 1.3
#~~~~~~~~
names <- if(labels==F){NULL} else{if(locNames==F){popvec} else{locNames[popvec]}}
xx=dist[popvec,popvec]
x=as.vector(cmdscale(xx,k=3)[,1])
y=as.vector(cmdscale(xx,k=3)[,2])
z=-as.vector(cmdscale(xx,k=3)[,3])
plot3d(x,y,z+abs(range(z)[1]),aspect=F,col=colors()[colvec[popvec]],size=size,type='s',main=main,box=box,axes=axes,top=T,cex=1,xlab='',ylab='',zlab='',xlen=0,ylen=0,zlen=0)
plot3d(x,y,z+abs(range(z)[1]),aspect=F,col="black",size=3,type='h',box=F,axes=F,top=T,add=T,xlab='',ylab='',zlab='',xlen=0,ylen=0,zlen=0)
if(labels==T){texts3d(x,y,z+abs(range(z)[1]),adj=adj,text=names,font=1,cex=cex,add=T,top=T,axes=F,xlab='',ylab='',zlab='')}
par3d(windowRect = c(0, 0, 2000, 2000))
legend3d("topright", legend = groups, pch = 16, col = cols, inset = c(0), cex = 5)
rglwidget()

Summary

Added 3 new collections:

  1. CMBARL17 - Barling Bay Creek - 9/1/2017
  2. CMKIAV17 - Kiavak Portage - 9/1/2017
  3. CMNATA17 - Natalia Bay Creek - 9/1/2017

Of note, the 2017 collection from Barling Bay Creek came from higher up in the drainaage (Birch Foster, personal communication), but still looks very similar to the 2015 September collection. Kiavak Portage is closely related to Barling, and Natalia was bit further away from the main cluster.

This update does not change any departmental recommendations regarding the use of local broodsource (Barling Bay Creek) for a chum hatchery in Old Harbor.

LS0tDQp0aXRsZTogIktvZGlhayBDaHVtIEJhc2VsaW5lIC0gMjAxOCBVcGRhdGUiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgdGhlbWU6IHVuaXRlZA0KICAgIHRvYzogeWVzDQplZGl0b3Jfb3B0aW9uczogDQogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgbWVzc2FnZT1GQUxTRSwgcmVzdWx0cz0naGlkZSd9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShsZWFmbGV0KQ0KbGlicmFyeShEVCkNCmxpYnJhcnkoZ2VuZXBvcCkNCmxpYnJhcnkoYWJpbmQpDQpiYmluZCA8LSBmdW5jdGlvbiguLi4pIHsgYWJpbmQoLi4uLCBhbG9uZyA9IDMpIH0NClN5cy5zZXRlbnYoUkdMX1VTRV9OVUxMID0gVFJVRSkNCmxpYnJhcnkocmdsKQ0KDQoudXNlcm5hbWUgPC0gImtyc2hlZGQiDQoucGFzc3dvcmQgPC0gIiINCnNvdXJjZSgifi8uLi9SL0Z1bmN0aW9ucy5HQ0wuUiIpDQpgYGANCg0KIyBJbnRyb2R1Y3Rpb24NCg0KIyMgUHVycG9zZQ0KDQpUaGlzIGlzIGEgcXVpY2sgYmFzZWxpbmUgdXBkYXRlIHRvIEFuZHkgQmFyY2xheSdzIDIwMTUgS29kaWFrIGNodW0gYmFzZWxpbmUuIFRoaXMgYmFzZWxpbmUgdXBkYXRlIGluY2x1ZGVzIDMgbmV3IGNvbGxlY3Rpb25zIHNhbXBsZWQgYnkgQURGJkcgc3RhZmYgKEJpcmNoIEZvc3RlcikgaW4gMjAxNzoNCg0KMSkgQ01CQVJMMTcgLSBCYXJsaW5nIEJheSBDcmVlayAtIDkvMS8yMDE3DQoyKSBDTUtJQVYxNyAtIEtpYXZhayBQb3J0YWdlIC0gOS8xLzIwMTcNCjMpIENNTkFUQTE3IC0gTmF0YWxpYSBCYXkgQ3JlZWsgLSA5LzEvMjAxNw0KDQojIyBCYWNrZ3JvdW5kDQoNCkFuZHkncyB3b3JrIGluIGxhdGUgMjAxNSB3YXMgZG9uZSB0byBhc3Nlc3MgcG9wdWxhdGlvbiBnZW5ldGljIHN0cnVjdHVyZSBvZiBjaHVtIHNhbG1vbiBpbiBTRSBLb2RpYWssIHNwZWNpZmljYWxseSBpbiB0aGUgVGhyZWUgU2FpbnRzIEJheSBhcmVhLiBLb2RpYWsgUmVnaW9uYWwgQXF1YWN1bHR1cmUgQXNzb2NpYXRpb24gKEtSQUEpIHdhbnRlZCB0byBlc3RhYmxpc2ggYSBuZXcgaGF0Y2hlcnkgaW4gT2xkIEhhcmJvciB0byBtYWtlIGVhcmx5LXJ1biBjaHVtIHNhbG1vbiBmb3IgYSByZW1vdGUgcmVsZWFzZSBzaXRlIGluIFRocmVlIFNhaW50cyBCYXkuIEtSQUEgaW50ZW5kZWQgdG8gdXNlIHRoZSBTdHVyZ2VvbiBicm9vZHN0b2NrLCB0aGF0IHRoZXkgYWxyZWFkeSB1c2UgZm9yIHRoZWlyIEtpdG9pIEJheSBmYWNpbGl0eS4gQURGJkcgcmVnaW9uYWwgc3RhZmYgaW5kaWNhdGVkIHRoYXQgdGhlcmUgYXJlIGtub3duIGVhcmx5LXJ1biBjaHVtIHN0b2NrcyBpbiB0aGUgVGhyZWUgU2FpbnRzIEJheSBhcmVhLCB3aGljaCB3b3VsZCBwcmVzZW50IGEgZ2VuZXRpYyByaXNrIHRvIHVzaW5nIFN0dXJnZW9uIFJpdmVyIGJyb29kc3RvY2sgaW4gdGhlIGFyZWEgKHNpbWlsYXIgcnVuIHRpbWluZywgYnV0IHBvdGVudGlhbGx5IGdlbmV0aWNhbGx5IGRpZmZlcmVudCkuIFJlZ2lvbmFsIHN0YWZmIGluZGljYXRlZCB0aGF0IEJhcmxpbmcgQmF5IENyZWVrIGluIHBhcnRpY3VsYXIgaGFkIGVhcmx5LXJ1biBjaHVtIHNhbG1vbi4gVGh1cywgcmVnaW9uYWwgc3RhZmYgY29sbGVjdGVkIHRlbXBvcmFsIHNhbXBsZXMgdGhyb3VnaG91dCB0aGUgc2Vhc29uIGZyb20gQmFybGluZyBCYXkgQ3JlZWsgYW5kIG90aGVyIG5lYXJieSBzeXN0ZW1zIHRvIGdldCBhIGJldHRlciB1bmRlcnN0YW5kaW5nIG9mIHBvcHVsYXRpb24gZ2VuZXRpYyBzdHJ1Y3R1cmUgaW4gU0UgS29kaWFrIHRvIGRldGVybWluZSB3aGV0aGVyIGVhcmx5LXJ1biBCYXJsaW5nIEJheSBDcmVlayBjaHVtIHdlcmUgc3VmZmljaWVudGx5IGRpc3RpbmN0IGZyb20gU3R1cmdlb24gUml2ZXIgY2h1bSB0byBiZSBhbiB1bmFjY3BldGFibGUgZ2VuZXRpYyByaXNrLiBVbHRpbWF0ZWx5LCBBbmR5J3Mgd29yayBkaWQgc2hvdyB0aGF0IEJhcmxpbmcgQmF5IENyZWVrIGhhcyBzaWduaWZpY2FudCB0ZW1wb3JhbCBnZW5ldGljIHN0cnVjdHVyZSB0aHJvdWdob3V0IHRoZSBzZWFzb24gKEp1bHkgdnMuIEF1Z3VzdCB2cy4gU2VwdGVtYmVyKS4gVGhlc2UgcmVzdWx0cyByZXN1bHRlZCBpbiBhIG1lbW8gd2l0aCBhIGRlcGFydG1lbnQgcmVjb21tZW5kYXRpb24gdG8gdXNlIGxvY2FsIGJyb29kc3RvY2sgKGVhcmx5LXJ1biBCYXJsaW5nIEJheSBDcmVlaykgcmF0aGVyIHRoYW4gU3R1cmdlb24gUml2ZXIgYnJvb2RzdG9jayBmcm9tIEtpdG9pIEJheSBmb3IgdGhlIFRocmVlIFNhaW50cyBCYXkgcHJvamVjdC4NCg0KVGhpcyAyMDE4IGJhc2VsaW5lIHVwZGF0ZSB3aWxsIGluY29ycG9yYXRlIHRocmVlIGFkZGl0aW9uYWwgY29sbGVjdGlvbnMgbWFkZSBieSBBREYmRyBzdGFmZi4gVGhlIHJlc3VsdHMgZnJvbSB0aGlzIGJhc2VsaW5lIHVwZGF0ZSBhcmUgbm90IGdvaW5nIHRvIGNoYW5nZSB0aGUgZGVjaXNpb24gcmVnYXJkaW5nIHVzZSBvZiBsb2NhbCBicm9vZHNvdXJjZSwgdGhleSBhcmUgaW50ZW5kZWQgdG8gcHJvdmlkZSBzb21lIGFkZGl0aW9uYWwgKnByZS1oYXRjaGVyeSogYmFzZWxpbmUuDQoNCiMjIE91dGxpbmUNCg0KVGhpcyBSIE5vdGVib29rIHdpbGwgcGVyZm9ybSB0aGUgZm9sbG93aW5nIHRhc2tzOg0KDQogICogUmVhZCBpbiBnZW5vdHlwZSBkYXRhDQogICAgKyBDcmVhdGUgKkxvY3VzQ29udHJvbCoNCiAgICArIFJlYWQgaW4gYWxsIHByb2plY3QgZ2Vub3R5cGVzDQogICogTWFwIG9mIGFsbCBiYXNlbGluZSBjb2xsZWN0aW9ucw0KICAqIFBvb2xpbmcgQmFybGluZyAyMDE1DQogICAgKyBTcGxpdCBgQ01CQVJMUjE1YCBpbnRvICplYXJseSosICptaWRkbGUqLCBhbmQgKmxhdGUqIGNvbGxlY3Rpb25zIChhcyBpbiB0aGUgMjAxNSBiYXNlbGluZSkNCiAgKiBEZXRlcm1pbmUgKkZhaWx1cmVSYXRlKg0KICAqIERhdGEgUUENCiAgICArIFJlbW92aW5nIGZpc2ggbWlzc2luZyA+PSAyMCUgb2YgZ2Vub3R5cGVzDQogICAgKyBSZW1vdmUgd2l0aGluIGNvbGxlY3Rpb24gZHVwbGljYXRlcw0KICAgICsgU2F2ZSBmaW5hbCwgcG9zdC1RQSBnZW5vdHlwZXMNCiAgKiBDaGVjayAqSFdFKiAtIGNvbGxlY3Rpb25zDQogICogUG9vbGluZyB0ZW1wb3JhbCBjb2xsZWN0aW9ucw0KICAqIENoZWNrICpIV0UqIC0gcG9wdWxhdGlvbnMNCiAgKiBNYXAgb2YgYWxsIGJhc2VsaW5lIHBvcHVsYXRpb25zDQogICogRXhwbG9yZSBnZW5ldGljIHN0cnVjdHVyZQ0KICAgICsgR2VuZXJhdGUgYWxsZWxlIGZyZXF1ZW5jeSBwbG90cw0KICAgICsgRnN0IHRyZWUNCiAgICArIE1EUyB1c2luZyBGc3QNCg0KIyBSZWFkIGluIGdlbm90eXBlIGRhdGENCg0KTmVlZCB0byBjcmVhdGUgKkxvY3VzQ29udHJvbCogZm9yIHRoZSBtYXJrZXJzIHdlIGFyZSB1c2luZyBhbmQgdGhlbiByZWFkIGluIGFsbCB0aGUgZ2Vub3R5cGUgZGF0YSBmb3IgdGhlIHNhbWUgY29sbGVjdGlvbnMgdGhhdCBBbmR5IGFuYWx5emVkIGluIDIwMTUgKyB0aGUgdGhyZWUgbmV3IGNvbGxlY3Rpb25zIGZyb20gMjAxNyAodGhlIHVwZGF0ZSkuDQoNCiMjIE1hcmtlcnNldA0KDQpUaGlzIGFuYWx5c2lzIGlzIHVzaW5nIHRoZSA5NiBTTlBzIGZyb20gV0FTU0lQLg0KYGBge3IgY3JlYXRlX2xvY3VzY29udHJvbH0NCkNyZWF0ZUxvY3VzQ29udHJvbC5HQ0wobWFya2Vyc3VpdGUgPSAiQ2h1bUdvbGRlbjIwMTFfOTZTTlBzIiwgdXNlcm5hbWUgPSAudXNlcm5hbWUsIHBhc3N3b3JkID0gLnBhc3N3b3JkKQ0KbG9jaTk2IDwtIExvY3VzQ29udHJvbCRsb2N1c25hbWVzDQoNCmRpci5jcmVhdGUoIi4uLzIwMTgvT2JqZWN0cyIpDQpzYXZlX29iamVjdHMoYygiTG9jdXNDb250cm9sIiwgImxvY2k5NiIpLCAiLi4vMjAxOC9PYmplY3RzIikNCmBgYA0KDQojIyBDb2xsZWN0aW9ucw0KDQpXZSB3YW50IHRvIGluY2x1ZGUgdGhlIHNhbWUgODYgY29sbGVjdGlvbnMgdXNlZCBieSBBbmR5IGluIGhpcyAyMDE1IGJhc2VsaW5lICsgdGhlIDMgbmV3IGNvbGxlY3Rpb25zIGZyb20gMjAxNy4NCmBgYHtyIGNvbGxlY3Rpb25zXzg5fQ0KKGNvbGxlY3Rpb25zXzg5IDwtIHJlYWRfY3N2KCIuLi8yMDE4L2NvbGxlY3Rpb25zODkuY3N2IikgJT4lIA0KICBwdWxsKCJzaWxseSIpKQ0Kc2F2ZV9vYmplY3RzKCJjb2xsZWN0aW9uc184OSIsICIuLi8yMDE4L09iamVjdHMvIikNCmBgYA0KDQpSZWFkIGluIGdlbm90eXBlIGRhdGEgZnJvbSBMT0tJLg0KYGBge3IgcmVhZF9sb2tpfQ0KTE9LSTJSLkdDTChzaWxseXZlYyA9IGNvbGxlY3Rpb25zXzg5LCB1c2VybmFtZSA9IC51c2VybmFtZSwgcGFzc3dvcmQgPSAucGFzc3dvcmQpDQpybSgudXNlcm5hbWUsIC5wYXNzd29yZCkNCg0KZGlyLmNyZWF0ZSgiLi4vMjAxOC9HZW5vdHlwZXMiKQ0KZGlyLmNyZWF0ZSgiLi4vMjAxOC9HZW5vdHlwZXMvb3JpZ2luYWwiKQ0Kc2F2ZV9zaWxseXMoY29sbGVjdGlvbnNfODksICIuLi8yMDE4L0dlbm90eXBlcy9vcmlnaW5hbCIpDQpgYGANCg0KIyBNYXAgb2YgYWxsIGJhc2VsaW5lIGNvbGxlY3Rpb25zDQoNClB1bGwgdGhlIGxhdGl0dWRlL2xvbmdpdHVkZSBkYXRhIGZvciBgY29sbGVjdGlvbnNfODlgIGZyb20gT2NlYW5BSywgbmVlZCB0byByZW1vdmUgIlVXIiBmcm9tIGFsbCBzaWxseXMgZm9yIGZpbHRlcmluZyB0byBnZXQgdGhlIHJlcG9ydC4NCmBgYHtyIGNvbGxlY3Rpb25zXzg5X29jZWFuYWt9DQp3cml0ZUNsaXBib2FyZChwYXN0ZShzdHJfcmVwbGFjZShjb2xsZWN0aW9uc184OSwgIlVXIiwgIiIpLCBjb2xsYXBzZSA9ICI7IikpDQpkaXIuY3JlYXRlKCIuLi8yMDE4L09jZWFuQUsiKQ0KYGBgDQoNCkNyZWF0ZSBhIG1hcCBvZiB0aGUgYmFzZWxpbmUgY29sbGVjdGlvbnMNCmBgYHtyIGNvbGxlY3Rpb25zXzg5X21hcH0NCnJlYWRfY3N2KCIuLi8yMDE4L09jZWFuQUsvY29sbGVjdGlvbnNfODlfSnVzdCB0aGUgTGF0X0xvbmdzLmNzdiIpICU+JSANCiAgbGVhZmxldCh3aWR0aCA9ICIxMDAlIikgJT4lIA0KICBhZGRUaWxlcygpICU+JSANCiAgYWRkTWFya2Vycyh+IExvbmdpdHVkZSwgfiBMYXRpdHVkZSwgbGFiZWwgPSB+IGBTaWxseSBDb2RlYCwgY2x1c3Rlck9wdGlvbnMgPSBtYXJrZXJDbHVzdGVyT3B0aW9ucygpKQ0KYGBgDQoNCkNyZWF0ZSBhbiBhd2Vzb21lIG1hcCBvZiB0aGUgYmFzZWxpbmUgY29sbGVjdGlvbnMNCmBgYHtyIGNvbGxlY3Rpb25zXzg5X2F3ZXNvbWVfbWFwfQ0KY29sbGVjdGlvbnNfODlfaW5mbyA8LSByZWFkX2NzdigiLi4vMjAxOC9PY2VhbkFLL2NvbGxlY3Rpb25zXzg5X0NvbGxlY3Rpb24gSW5mb19tb2QuY3N2IikgDQoNCmNvbGxlY3Rpb25zXzg5X2luZm8gJT4lIA0KICBjb3VudChRdWFkcmFudCkNCg0KY29sbGVjdGlvbnNfODlfaW5mbyA8LSBjb2xsZWN0aW9uc184OV9pbmZvICU+JSANCiAgbXV0YXRlKGNvbG9yID0gY2FzZV93aGVuKFF1YWRyYW50ID09ICJQZW5pbnN1bGEgLSBTb3V0aCIgfiAicmVkIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFF1YWRyYW50ID09ICJDaGlnbmlrIiB+ICJvcmFuZ2UiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgUXVhZHJhbnQgPT0gIktvZGlhayBNYWlubGFuZCIgfiAiYmx1ZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBRdWFkcmFudCA9PSAiS29kaWFrL0Fmb2duYWsgSXNsYW5kcyIgfiAicHVycGxlIikpDQoNCmljb25zIDwtIGF3ZXNvbWVJY29ucyhpY29uID0gJ2lvcy1jbG9zZScsIGljb25Db2xvciA9ICdibGFjaycsIGxpYnJhcnkgPSAnaW9uJywgbWFya2VyQ29sb3IgPSBjb2xsZWN0aW9uc184OV9pbmZvJGNvbG9yKQ0KDQpjb2xsZWN0aW9uc184OV9pbmZvICU+JSANCiAgbGVhZmxldCh3aWR0aCA9ICIxMDAlIikgJT4lIA0KICBhZGRUaWxlcygpICU+JSANCiAgYWRkQXdlc29tZU1hcmtlcnMofiBMb25naXR1ZGUsIH4gTGF0aXR1ZGUsIGljb24gPSBpY29ucywgbGFiZWwgPSB+IGBTaWxseSBDb2RlYCkNCmBgYA0KDQojIFBvb2xpbmcgQmFybGluZyAyMDE1DQoNCldlIG5lZWQgdG8gc3BsaXQgYENNQkFSTFIxNWAgaW50byAqZWFybHkqLCAqbWlkZGxlKiwgYW5kICpsYXRlKiBjb2xsZWN0aW9ucyAoYXMgaW4gdGhlIDIwMTUgYmFzZWxpbmUpLCBhcyB0aGlzICpzaWxseSogcmVwcmVzZW50cyAzIGRpc3RpbmN0IGNvbGxlY3Rpb25zLg0KYGBge3IgYmFybGluZ19kYXRlc30NCnRhYmxlKENNQkFSTFIxNS5nY2wkYXR0cmlidXRlcyRDQVBUVVJFX0RBVEUpDQpgYGANCg0KVXNlIGBBdHRyaWJ1dGVzVG9JRHMuR0NMYCB0byBzcGxpdCBieSBkYXRlIGFuZCBwb29sIGludG8gbmV3IHNpbGx5J3MuDQpgYGB7ciBiYXJsaW5nX3NwbGl0fQ0KIyBlYXJseQ0KQ01CQVJMUjE1X2Vhcmx5X2lkcyA8LSBBdHRyaWJ1dGVzVG9JRHMuR0NMKHNpbGx5ID0gIkNNQkFSTFIxNSIsIGF0dHJpYnV0ZSA9ICJDQVBUVVJFX0RBVEUiLCBtYXRjaGluZyA9ICIyMDE1LTA3LTA5IikNClBvb2xDb2xsZWN0aW9ucy5HQ0woY29sbGVjdGlvbnMgPSAiQ01CQVJMUjE1IiwgbG9jaSA9IGxvY2k5NiwgSURzID0gbGlzdChDTUJBUkxSMTUgPSBDTUJBUkxSMTVfZWFybHlfaWRzKSwgbmV3bmFtZSA9ICJDTUJBUkxSMTVFIikNCg0KIyBtaWRkbGUNCkNNQkFSTFIxNV9taWRkbGVfaWRzIDwtIEF0dHJpYnV0ZXNUb0lEcy5HQ0woc2lsbHkgPSAiQ01CQVJMUjE1IiwgYXR0cmlidXRlID0gIkNBUFRVUkVfREFURSIsIG1hdGNoaW5nID0gIjIwMTUtMDgtMDMiKQ0KUG9vbENvbGxlY3Rpb25zLkdDTChjb2xsZWN0aW9ucyA9ICJDTUJBUkxSMTUiLCBsb2NpID0gbG9jaTk2LCBJRHMgPSBsaXN0KENNQkFSTFIxNSA9IENNQkFSTFIxNV9taWRkbGVfaWRzKSwgbmV3bmFtZSA9ICJDTUJBUkxSMTVNIikNCg0KIyBsYXRlDQpDTUJBUkxSMTVfbGF0ZV9pZHMgPC0gQXR0cmlidXRlc1RvSURzLkdDTChzaWxseSA9ICJDTUJBUkxSMTUiLCBhdHRyaWJ1dGUgPSAiQ0FQVFVSRV9EQVRFIiwgbWF0Y2hpbmcgPSAiMjAxNS0wOS0xMSIpDQpQb29sQ29sbGVjdGlvbnMuR0NMKGNvbGxlY3Rpb25zID0gIkNNQkFSTFIxNSIsIGxvY2kgPSBsb2NpOTYsIElEcyA9IGxpc3QoQ01CQVJMUjE1ID0gQ01CQVJMUjE1X2xhdGVfaWRzKSwgbmV3bmFtZSA9ICJDTUJBUkxSMTVMIikNCg0Kc2F2ZV9zaWxseXMoYygiQ01CQVJMUjE1RSIsICJDTUJBUkxSMTVNIiwgIkNNQkFSTFIxNUwiKSwgIi4uLzIwMTgvR2Vub3R5cGVzL29yaWdpbmFsLyIpDQpgYGANCg0KTm93IGNyZWF0ZSBhIG5ldyAqc2lsbHl2ZWMqIHdpdGggdGhlIHRocmVlIHRlbXBvcmFsIDIwMTUgQmFybGluZyBjb2xsZWN0aW9ucyBzcGxpdCBvdXQgYW5kIHRoZSBvcmlnaW5hbCBgQ01CQVJMUjE1YCByZW1vdmVkLiBQbGFubmluZyB0byBzb3J0IGZvciBlYXNlIG9mIHVzZS4NCmBgYHtyIGNvbGxlY3Rpb25zXzkxfQ0KKGNvbGxlY3Rpb25zXzkxIDwtIHNvcnQoYyhjb2xsZWN0aW9uc184OVtjb2xsZWN0aW9uc184OSAhPSAiQ01CQVJMUjE1Il0sICJDTUJBUkxSMTVFIiwgIkNNQkFSTFIxNU0iLCAiQ01CQVJMUjE1TCIpKSkNCnNhdmVfb2JqZWN0cygiY29sbGVjdGlvbnNfOTEiLCAiLi4vMjAxOC9PYmplY3RzLyIpDQpgYGANCg0KU2F2ZSBzaWxseXMgcG9zdCBzcGxpdC4NCmBgYHtyIHNhdmVfY29sbGVjdGlvbnNfOTF9DQpkaXIuY3JlYXRlKCIuLi8yMDE4L0dlbm90eXBlcy9vcmlnaW5hbF9zcGxpdCIpDQpzYXZlX3NpbGx5cyhjb2xsZWN0aW9uc185MSwgIi4uLzIwMTgvR2Vub3R5cGVzL29yaWdpbmFsX3NwbGl0IikNCmBgYA0KDQojIERldGVybWluZSAqRmFpbHVyZVJhdGUqDQoNCmBgYHtyIGZhaWx1cmVfcmF0ZX0NCnByb2plY3QgPC0gIndlc3R3YXJkX2NodW1fYmFzZWxpbmUiDQpsb2NpIDwtIGxvY2k5Ng0KKGZhaWx1cmVfcmF0ZSA8LSBGYWlsdXJlUmF0ZS5HQ0woc2lsbHl2ZWMgPSBjb2xsZWN0aW9uc185MSkpDQpmYWlsdXJlX3JhdGVfbm9wbG90cyA8LSBmYWlsdXJlX3JhdGVbMTo0XQ0Kc2F2ZV9vYmplY3RzKCJmYWlsdXJlX3JhdGVfbm9wbG90cyIsICIuLi8yMDE4L09iamVjdHMvIikNCmBgYA0KDQpBbHNvIGNhbGN1bGF0ZSBzYW1wbGUgc2l6ZSBieSBsb2N1cyBhbmQgc2F2ZS4NCmBgYHtyfQ0KKHNhbXBsZV9zaXplX2J5X2xvY3VzIDwtIFNhbXBTaXplQnlMb2N1cy5HQ0woc2lsbHl2ZWMgPSBjb2xsZWN0aW9uc185MSwgbG9jaSA9IGxvY2k5NikgJT4lIA0KICBhc190aWJibGUocm93bmFtZXMgPSAic2lsbHkiKSkNCg0KZGlyLmNyZWF0ZSgiLi4vMjAxOC9UYWJsZXMiKQ0Kd3JpdGVfY3N2KHNhbXBsZV9zaXplX2J5X2xvY3VzLCAiLi4vMjAxOC9UYWJsZXMvc2FtcGxlX3NpemVfYnlfbG9jdXMuY3N2IikNCmBgYA0KDQojIERhdGEgUUENCg0KUGVyZm9ybSBzdGFuZGFyZCBkYXRhIFFBIHByb2Nlc3NlcyB0byBmaWx0ZXIgb3V0IHVudHJ1c3R3b3J0aCBnZW5vdHlwZXMuDQpgYGB7ciBxYV9zZXR1cH0NCnNhbXBsZV9zaXplX3FhIDwtIHRpYmJsZShzaWxseSA9IGNvbGxlY3Rpb25zXzkxKSAlPiUgDQogIG11dGF0ZShnZW5vdHlwZWQgPSBzYXBwbHkoc2lsbHksIGZ1bmN0aW9uKHgpIGdldChwYXN0ZTAoeCwgIi5nY2wiKSkkbikpDQpgYGANCg0KIyMgTWlzc2luZw0KDQpSZW1vdmUgaW5kaXZpZHVhbHMgbWlzc2luZyA+PTIwJSBvZiBnZW5vdHlwZXMgKGkuZS4gdGhlIDgwJSBydWxlKS4NCmBgYHtyIHFhX21pc3Npbmd9DQptaXNzX2xvY2kgPC0gUmVtb3ZlSW5kTWlzc0xvY2kuR0NMKHNpbGx5dmVjID0gY29sbGVjdGlvbnNfOTEsIHByb3BvcnRpb24gPSAwLjgpDQpzYXZlX29iamVjdHMoIm1pc3NfbG9jaSIsICIuLi8yMDE4L09iamVjdHMvIikNCg0KIyBzaG93IGluZGl2aWR1YWxzIHJlbW92ZWQNCm1pc3NfbG9jaVttaXNzX2xvY2kgIT0gIk5vbmUiXQ0KDQpzYW1wbGVfc2l6ZV9xYSA8LSBzYW1wbGVfc2l6ZV9xYSAlPiUgDQogIG11dGF0ZShtaXNzaW5nID0gZ2Vub3R5cGVkIC0gc2FwcGx5KHNpbGx5LCBmdW5jdGlvbih4KSBnZXQocGFzdGUwKHgsICIuZ2NsIikpJG4pKQ0KYGBgDQoNCiMjIER1cGxpY2F0ZQ0KDQpSZW1vdmUgZHVwbGljYXRlIGluZGl2aWR1YWxzIHdpdGhpbiB0aGUgc2FtZSBjb2xsZWN0aW9uLiBUeXBpY2FsbHkgd2Ugc3BlY2lmeSAqZHVwbGljYXRlcyogYXMgYSBwYWlyIG9mIGluZGl2aWR1YWxzIHRoYXQgc2hhcmUgPj05NSUgb2YgZ2Vub3R5cGVzLiBPbmNlIGEgcGFpciBvZiAqZHVwbGljYXRlcyogaXMgaWRlbnRpZmllZCwgd2Uga2VlcCB0aGUgaW5kaXZpZHVhbCB3aXRoIHRoZSBtb3N0IGdlbm90eXBlcyBhbmQgcmVtb3ZlIHRoZSBvdGhlci4NCmBgYHtyIHFhX2R1cGxpY2F0ZX0NCmR1cGxpY2F0ZV9jaGVja185NSA8LSBDaGVja0R1cFdpdGhpblNpbGx5LkdDTChzaWxseXZlYyA9IGNvbGxlY3Rpb25zXzkxLCBsb2NpID0gbG9jaTk2LCBxdWFudGlsZSA9IE5VTEwsIG1pbnByb3BvcnRpb24gPSAwLjk1KQ0KZHVwbGljYXRlX3N1bW1hcnkgPC0gc2FwcGx5KGNvbGxlY3Rpb25zXzkxLCBmdW5jdGlvbih4KSBkdXBsaWNhdGVfY2hlY2tfOTVbW3hdXSRyZXBvcnQsIHNpbXBsaWZ5ID0gRkFMU0UpDQpkdXBsaWNhdGVfcmVtb3ZlIDwtIFJlbW92ZUR1cHMuR0NMKGR1cGxpY2F0ZV9jaGVja185NSkNCnNhdmVfb2JqZWN0cyhjKCJkdXBsaWNhdGVfc3VtbWFyeSIsICJkdXBsaWNhdGVfcmVtb3ZlIiksICIuLi8yMDE4L09iamVjdHMvIikNCg0KIyBzaG93IGluZGl2aWR1YWxzIHJlbW92ZWQNCmR1cGxpY2F0ZV9yZW1vdmVbZHVwbGljYXRlX3JlbW92ZSAhPSAiTm90aGluZyBSZW1vdmVkIl0NCg0Kc2FtcGxlX3NpemVfcWEgPC0gc2FtcGxlX3NpemVfcWEgJT4lIA0KICBtdXRhdGUoZHVwbGljYXRlID0gZ2Vub3R5cGVkIC0gbWlzc2luZyAtIHNhcHBseShzaWxseSwgZnVuY3Rpb24oeCkgZ2V0KHBhc3RlMCh4LCAiLmdjbCIpKSRuKSkNCmBgYA0KDQojIyBGaW5hbA0KDQpIb3cgbWFueSBmaXNoIGRpZCB3ZSBlbmQgdXAgd2l0aCBpbiBvdXIgZmluYWwgYmFzZWxpbmU/IFNhdmUgZmluYWwgZ2Vub3R5cGVzLg0KYGBge3IgcWFfZmluYWx9DQooc2FtcGxlX3NpemVfcWEgPC0gc2FtcGxlX3NpemVfcWEgJT4lIA0KICBtdXRhdGUoZmluYWwgPSBzYXBwbHkoc2lsbHksIGZ1bmN0aW9uKHgpIGdldChwYXN0ZTAoeCwgIi5nY2wiKSkkbikpKQ0Kd3JpdGVfY3N2KHNhbXBsZV9zaXplX3FhLCAiLi4vMjAxOC9UYWJsZXMvc2FtcGxlX3NpemVfcWEuY3N2IikNCg0KZGlyLmNyZWF0ZSgiLi4vMjAxOC9HZW5vdHlwZXMvb3JpZ2luYWxfc3BsaXRfcG9zdFFBLyIpDQpzYXZlX3NpbGx5cyhjb2xsZWN0aW9uc185MSwgIi4uLzIwMTgvR2Vub3R5cGVzL29yaWdpbmFsX3NwbGl0X3Bvc3RRQS8iKQ0KYGBgDQoNCldoYXQgaXMgc21hbGxlc3QgY29sbGVjdGlvbj8NCmBgYHtyIHFhX2FycmFuZ2V9DQpzYW1wbGVfc2l6ZV9xYSAlPiUgDQogIGFycmFuZ2UoZmluYWwpDQpgYGANCg0KV2hvYSwgd2Ugc2hvdWxkIHRvdGFsbHkganVuayBzb21lIG9mIHRoZXNlIGNvbGxlY3Rpb25zIGdpdmVuIHRoZWlyIGxvdyBzYW1wbGUgc2l6ZSAob3IgY29tcGxldGUgbGFjayBvZiBmaXNoISkuIFdlJ2xsIGtlZXAgYW55dGhpbmcgd2l0aCBhdCBsZWFzdCA0MCBmaXNoLg0KYGBge3IgY29sbGVjdGlvbnNfODh9DQooY29sbGVjdGlvbnNfODggPC0gc2FtcGxlX3NpemVfcWEgJT4lIA0KICAgZmlsdGVyKGZpbmFsID4gNDApICU+JSANCiAgIHB1bGwoInNpbGx5IikpDQpzYXZlX29iamVjdHMoImNvbGxlY3Rpb25zXzg4IiwgIi4uLzIwMTgvT2JqZWN0cy8iKQ0KYGBgDQoNCiMgQ2hlY2sgKkhXRSogLSBjb2xsZWN0aW9ucw0KDQpXcml0ZSBvdXQgYSAqR2VuZXBvcCogZmlsZSB0byBjaGVjayBIV0Ugd2l0aGluIGNvbGxlY3Rpb25zLg0KYGBge3Igd3JpdGVfZ2VuZXBvcH0NCmRpci5jcmVhdGUoIi4uLzIwMTgvR2VuZXBvcCIpDQpnY2wyR2VuZXBvcC5HQ0woc2lsbHl2ZWMgPSBjb2xsZWN0aW9uc184OCwgbG9jaSA9IGxvY2k5NiwgcGF0aCA9ICIuLi8yMDE4L0dlbmVwb3AvY29sbGVjdGlvbnNfODguZ2VuIiwgVmlhbE51bXMgPSBUUlVFKQ0KYGBgDQoNCkNhbGN1bGF0ZSBIV0UgdXNpbmcgdGhlICpnZW5lcG9wKiBwYWNrYWdlIFtsaW5rXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvZ2VuZXBvcC9pbmRleC5odG1sKS4NCmBgYHtyIGNvbGxlY3Rpb25zXzg4X2h3ZX0NCnRlc3RfSFcoaW5wdXRGaWxlID0gIi4uLzIwMTgvR2VuZXBvcC9jb2xsZWN0aW9uc184OC5nZW4iLCBvdXRwdXRGaWxlID0gIi4uLzIwMTgvR2VuZXBvcC9jb2xsZWN0aW9uc184OC50eHQuUCIpDQpgYGANCg0KIyMgU3VtbWFyeSB0YWJsZQ0KUmVhZCBpbiByZXN1bHRzIGFuZCBzYXZlIHN1bW1hcnkgSFdFIHAtdmFsdWVzLg0KYGBge3IgaHdlX3Jlc3VsdHN9DQpod2VfY29sbGVjdGlvbnNfODggPC0gUmVhZEdlbmVwb3BIV0UuR0NMKGZpbGUgPSAiLi4vMjAxOC9HZW5lcG9wL2NvbGxlY3Rpb25zXzg4LnR4dC5QIiwgc2lsbHl2ZWMgPSBjb2xsZWN0aW9uc184OCkNCihod2Vfc3VtbWFyeV9jb2xsZWN0aW9uc184OCA8LSBod2VfY29sbGVjdGlvbnNfODgkU3VtbWFyeVBWYWx1ZXMgJT4lIA0KICBhc190aWJibGUocm93bmFtZXMgPSAibG9jdXMiKSkNCndyaXRlX2Nzdih4ID0gaHdlX3N1bW1hcnlfY29sbGVjdGlvbnNfODgsICIuLi8yMDE4L1RhYmxlcy9od2Vfc3VtbWFyeV9jb2xsZWN0aW9uc184OC5jc3YiKQ0KYGBgDQoNCiMjIyBDb2xsZWN0aW9ucyBvdXQgb2YgSFdQDQpXaGF0IGRvIG92ZXJhbGwtbG9jaSBwLXZhbHVlcyBsb29rIGxpa2UgZm9yIGNvbGxlY3Rpb25zPw0KYGBge3IgaHdlX292ZXJhbGxfbG9jaX0NCmh3ZV9zdW1tYXJ5X2NvbGxlY3Rpb25zXzg4ICU+JSANCiAgZ2F0aGVyKHNpbGx5LCBwLCAtbG9jdXMpICU+JQ0KICBmaWx0ZXIobG9jdXMgPT0gIk92ZXJhbGwgTG9jaSIpICU+JSANCiAgYXJyYW5nZShwKQ0KYGBgDQoNCkFsbCBsb29rIHByZXR0eSBnb29kIHdpdGggdGhlIHBvdGVudGlhbCBleGNlcHRpb24gb2YgYENNQkFSTFIxNUxgLg0KDQojIyMgTG9jaSBvdXQgb2YgSFdQDQpXaGF0IGRvIG92ZXJhbGwtbG9jaSBwLXZhbHVlcyBsb29rIGxpa2UgZm9yIGxvY2k/DQpgYGB7ciBod2Vfb3ZlcmFsbF9wb3BzfQ0KaHdlX3N1bW1hcnlfY29sbGVjdGlvbnNfODggJT4lIA0KICBnYXRoZXIoc2lsbHksIHAsIC1sb2N1cykgJT4lDQogIGZpbHRlcihzaWxseSA9PSAiT3ZlcmFsbCBQb3BzIikgJT4lIA0KICBhcnJhbmdlKHApDQpgYGANCg0KVGhlcmUgYXJlIGEgY291cGxlIG9mIGxvY2kgdGhhdCBhcmUgc3VzcGVjdC4NCg0KIyMgSFdQIHBsb3RzDQoNClBlciBXYXBsZXMgMjAxNCwgd2Ugd2lsbCBwbG90IGEgaGlzdG9ncmFtIG9mIEhXUCBwLXZhbHVlcyB0byBsb29rIGZvciBjb2xsZWN0aW9ucy9sb2NpIHRoYXQgZG8gbm90IGNvbmZvcm0gdG8gSFdQLiBXZSB3aWxsIGxpbWl0IG91ciBzZWFyY2ggdG8gdGhlIHNwZWNpZmljIGNvbGxlY3Rpb24gYW5kIGxvY2kgdGhhdCB3ZXJlIHN1c3BpY2lvdXMuDQoNCiMjIyBDb2xsZWN0aW9uDQoNClBsb3QgcC12YWx1ZXMgcGVyIGxvY3VzIGZvciBgQ01CQVJMUjE1TGANCmBgYHtyIGh3ZV9wbG90X0NNQkFSTFIxNUx9DQpod2Vfc3VtbWFyeV9jb2xsZWN0aW9uc184OCAlPiUgDQogIGdhdGhlcihzaWxseSwgcCwgLWxvY3VzKSAlPiUNCiAgZmlsdGVyKHNpbGx5ID09ICJDTUJBUkxSMTVMIikgJT4lIA0KICBmaWx0ZXIobG9jdXMgIT0gIk92ZXJhbGwgTG9jaSIpICU+JSANCiAgZ2dwbG90KGFlcyhwKSkgKyANCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjA1KSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDUsIGNvbG91ciA9ICJyZWQiKSArDQogIGdndGl0bGUoIkhXUCBwLXZhbHVlcyBieSBsb2N1cyBmb3IgQ01CQVJMUjE1TCIpDQpgYGANCg0KTG9va3MgZmluZSwgbm8gbWFqb3IgY2F1c2UgZm9yIGNvbmNlcm4sIG5vdyBvbiB0byBwbG90dGluZyBmb3IgbG9jaS4NCg0KIyMjIExvY2kNCg0KUGxvdCBwLXZhbHVlcyBwZXIgY29sbGVjdGlvbiBmb3IgbG9jaSB3aXRoIG92ZXJhbGwgcG9wcyBwLXZhbHVlIDwgMC4yLg0KYGBge3IgaHdlX3Bsb3RfbG9jaX0NCiMgZmlsdGVyIGZvciBsb2NpIHdpdGggb3ZlcmFsbCBwb3BzIDwgMC4yDQpod2VfbG9jaV9wbG90IDwtIGh3ZV9zdW1tYXJ5X2NvbGxlY3Rpb25zXzg4ICU+JSANCiAgZ2F0aGVyKHNpbGx5LCBwLCAtbG9jdXMpICU+JQ0KICBmaWx0ZXIoc2lsbHkgPT0gIk92ZXJhbGwgUG9wcyIgJiBwIDwgMC4yKSAlPiUgDQogIHB1bGwobG9jdXMpDQoNCiMgcGxvdA0KaHdlX3N1bW1hcnlfY29sbGVjdGlvbnNfODggJT4lIA0KICBnYXRoZXIoc2lsbHksIHAsIC1sb2N1cykgJT4lDQogIGZpbHRlcihsb2N1cyAlaW4lIGh3ZV9sb2NpX3Bsb3QpICU+JSANCiAgZmlsdGVyKHNpbGx5ICE9ICJPdmVyYWxsIFBvcHMiKSAlPiUNCiAgZ2dwbG90KGFlcyhwKSkgKyANCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjA1KSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGxlbmd0aChjb2xsZWN0aW9uc184OCkgLyAyMCwgY29sb3VyID0gInJlZCIpICsNCiAgZ2d0aXRsZSgiSFdQIHAtdmFsdWVzIGJ5IGNvbGxlY3Rpb24iKSArDQogIGZhY2V0X2dyaWQoIH4gbG9jdXMpDQpgYGANCg0KT2tlX1UyMDQxLTg0IGFuZCBPa2VfVTUwNi0xMTAgYXJlIGEgYml0IHN1c3BlY3QsIGJ1dCB3ZSdsbCBsZXQgdGhlbSBnbyBzaW5jZSB0aGVpciBvdmVyYWxsIHAtdmFsdWVzIHdlcmUgPiAwLjA1Lg0KDQojIyBUYWtlYXdheQ0KDQpBbGwgY29sbGVjdGlvbnMgYW5kIGxvY2kgd2VyZSByZXRhaW5lZC4NCg0KIyBQb29saW5nIHRlbXBvcmFsIGNvbGxlY3Rpb25zDQoNCk5vdyBJJ2xsIGZvbGxvdyBBbmR5J3MgcG9vbGluZyBvZiB0ZW1wb3JhbCBjb2xsZWN0aW9ucyBpbiB0byAqcG9wdWxhdGlvbnMqLg0KYGBge3IgdGVtcG9yYWxfcG9vbGluZ19jaGVja30NCmNvbGxlY3Rpb25zXzg5X2luZm8gJT4lIA0KICBhcnJhbmdlKExvY2F0aW9uKQ0KYGBgDQoNCiMjIE5vbi1CYXJsaW5nDQoNCiMjIyBBbmR5J3MNCg0KQ3JlYXRlIGEgbGlzdCBmb3IgcG9vbGluZyAoZXhjbHVkaW5nIEJhcmxpbmcpLiAqKk5vdGUqKiBzb21lIGFyZSBkaWZmZXJlbnQgdGhhbiBBbmR5J3MgKGkuZS4gU3RlcG92YWspDQpgYGB7ciB0ZW1wb3JhbF9wb29saW5nX2xpc3R9DQp0ZW1wb3JhbF9wb29saW5nIDwtIGxpc3QoIkFtYmVyIEJheSIgPSBjKCJDTVdFU045M1VXIiwgIkNNQU1CTTA5VVciKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAiQmFsYm9hIEJheSIgPSBjKCJDSEJBTDkyVVciLCAiQ01GT1NUMDlVVyIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICJIYWxsbyBCYXkiID0gYygiQ01XRVNIOTNVVyIsICJDTUJJR1JJMDlVVyIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICJCZWFyIEJheSIgPSBjKCJDTVdFU0Q5M1VXIiwgIkNNQkVBUkJDMDlVVyIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICJCaWcgU3VraG9pIiA9IGMoIkNNQlNVOTJVVyIsICJDTUJTVUswOVVXIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgIkNhbm9lIEJheSIgPSBjKCJDTUNBTjkyVVciLCAiQ01DQU4wOVVXIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgIkNoaWNoYWdvZiBCYXkiID0gYygiQ01DSEk5NlVXIiwgIkNNQ0hJMDlVVyIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICJDaGlnbmlhZ2FrIEJheSIgPSBjKCJDTVdFU0k5M1VXIiwgIkNNQ0hJR0swOVVXIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgIkd1bGwgQ2FwZSBDcmVlayIgPSBjKCJDTVdFU1A5M1VXIiwgIkNNR1VMTEMwOVVXIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgIkl2YW5vZiBSaXZlciIgPSBjKCJDTVdFU0w5M1VXIiwgIkNNSVZBTjA5VVciKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAiS2lhbGFndmlrIENyZWVrIiA9IGMoIkNNV0VTRjkzVVciLCAiQ01LSUFMMDlVVyIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICJLaXRvaSBCYXkiID0gYygiQ01XRVNBOTNVVyIsICJDTUtJVEIwOVVXIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgIktpemh1eWFrIFJpdmVyIiA9IGMoIkNIS0laOTJVVyIsICJDTUtJWkgwOVVXIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgIkt1anVsaWsgQmF5IiA9IGMoIkNNV0VTSzkzVVciLCAiQ01LVUpVTkYwOVVXIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgIkxpdHRsZSBKb2huIExhZ29vbiIgPSBjKCJDSExJSjkyVVciLCAiQ01MSUowOVVXIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgIlBvcnRhZ2UgQ3JlZWsiID0gYygiQ01XRVNKOTNVVyIsICJDTVBPUlRDMDhVVyIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICJSdXNzZWxsIENyZWVrIiA9IGMoIkNNUlVTOTJVVyIsICJDTVJVUzkzVVciLCAiQ01SVVMwOVVXIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgIlJ1c3NpYW4gUml2ZXIiID0gYygiQ01SVVNTSTA3VVciLCAiQ01SVVNTSTA5VVciKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAiU2FuZHkgQ292ZSIgPSBjKCJDTVNBTkM5NlVXIiwgIkNNU0FOQzA5VVciKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAiU3RlcG92YWsgQmF5IiA9IGMoIkNNU1RFOTJVVyIsICJDTVdFU005M1VXIiwgIkNNU1RFMDlVVyIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICJVZ2FuaWsgUml2ZXIiID0gYygiQ0hVR0E5MlVXIiwgIkNNVUdBTjA5VVciKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAiVm9sY2FubyBCYXkiID0gYygiQ01WT0w5MlVXIiwgIkNNVk9MOTZVVyIsICJDTVZPTDA5VVciKQ0KKQ0Kc2F2ZV9vYmplY3RzKCJ0ZW1wb3JhbF9wb29saW5nIiwgIi4uLzIwMTgvT2JqZWN0cy8iKQ0KDQojIHZlcmlmeSB0aGF0IGFsbCBzaWxseXMgYXJlIGluIGNvbGxlY3Rpb25zXzg4DQpzZXRkaWZmKHVubGlzdCh0ZW1wb3JhbF9wb29saW5nKSwgY29sbGVjdGlvbnNfODgpDQpgYGANCg0KTm93IHRoYXQgd2UgaGF2ZSBvdXIgbGlzdCBvZiBwdXRhdGl2ZSBwb3B1bGF0aW9ucyB0byBwb29sLCBsZXQncyBzZWUgaG93IHRoZXkgZG8gaW4gRmlzaGVyJ3MgdGVzdC4NCmBgYHtyIHRlbXBvcmFsX3Bvb2xpbmdfZmlzaGVycywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmNvbGxlY3Rpb25zXzg4X2FsbGVsZV9mcmVxIDwtIEZyZXFQb3AuR0NMKHNpbGx5dmVjID0gY29sbGVjdGlvbnNfODgsIGxvY2kgPSBsb2NpOTYpDQp0ZW1wb3JhbF9wb29saW5nX3Jlc3VsdHMgPC0gRmlzaGVyc1Rlc3QuR0NMKGZyZXEgPSBjb2xsZWN0aW9uc184OF9hbGxlbGVfZnJlcSwgbG9jaSA9IGxvY2k5NiwgdGVzdHMgPSB0ZW1wb3JhbF9wb29saW5nKQ0Kc2F2ZV9vYmplY3RzKGMoImNvbGxlY3Rpb25zXzg4X2FsbGVsZV9mcmVxIiwgInRlbXBvcmFsX3Bvb2xpbmdfcmVzdWx0cyIpLCAiLi4vMjAxOC9PYmplY3RzLyIpDQoNCiMgb3ZlcmFsbCBsb2NpIHAtdmFsdWVzDQp0ZW1wb3JhbF9wb29saW5nX3Jlc3VsdHMkT3ZlcmFsbFJlc3VsdHMgJT4lIA0KICBhc190aWJibGUocm93bmFtZXMgPSAicG9wIikgJT4lIA0KICBhcnJhbmdlKG92ZXJhbGwpDQpgYGANCg0KIyMjIFdBU1NJUA0KDQpJIHdlbnQgYW5kIGRvdWJsZSBjaGVja2VkIHRoZSBXQVNTSVAgY2h1bSBiYXNlbGluZSBbU1AgMTItMjZdKGh0dHA6Ly93d3cuYWRmZy5hbGFza2EuZ292L0ZlZEFpZHBkZnMvU1AxMi0yNi5wZGYpLCBUYWJsZSAyLiBTaG91bGQgaGF2ZSBkb25lIHRoaXMgZmlyc3QuDQoNCiAgKiBUaGUgMTk5MiBhbmQgMTk5NiBWb2xjYW5vIEJheSBjb2xsZWN0aW9ucyBnb3QgZHJvcHBlZCAoLUNNVk9MOTJVVywgLUNNVk9MOTZVVykNCiAgKiBQb29sIFN0ZXBvdmFrIEJheSAxOTkyIGFuZCAyMDA5LCBrZWVwIFN0ZXBvdmFrIFJpdmVyIDIwMDkgc2VwYXJhdGUsIGRyb3AgMTk5MyBTdGVwb3ZhayBSaXZlciAoLUNNV0VTTTkzVVcpDQogICogRHJvcCBBbWJlciBCYXkgMTk5MyAoLUNNV0VTTjkzVVcpDQogICogRHJvcCBIYWxsbyBCYXkgMTk5MyAoLUNNV0VTSDkzVVcpDQoNCmBgYHtyIHRlbXBvcmFsX3Bvb2xpbmdfV0FTU0lQfQ0KdGVtcG9yYWxfcG9vbGluZ19XQVNTSVAgPC0gbGlzdCgiQmFsYm9hIEJheSIgPSBjKCJDSEJBTDkyVVciLCAiQ01GT1NUMDlVVyIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQmVhciBCYXkiID0gYygiQ01XRVNEOTNVVyIsICJDTUJFQVJCQzA5VVciKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJpZyBTdWtob2kiID0gYygiQ01CU1U5MlVXIiwgIkNNQlNVSzA5VVciKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNhbm9lIEJheSIgPSBjKCJDTUNBTjkyVVciLCAiQ01DQU4wOVVXIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDaGljaGFnb2YgQmF5IiA9IGMoIkNNQ0hJOTZVVyIsICJDTUNISTA5VVciKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNoaWduaWFnYWsgQmF5IiA9IGMoIkNNV0VTSTkzVVciLCAiQ01DSElHSzA5VVciKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkd1bGwgQ2FwZSBDcmVlayIgPSBjKCJDTVdFU1A5M1VXIiwgIkNNR1VMTEMwOVVXIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJdmFub2YgUml2ZXIiID0gYygiQ01XRVNMOTNVVyIsICJDTUlWQU4wOVVXIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJLaWFsYWd2aWsgQ3JlZWsiID0gYygiQ01XRVNGOTNVVyIsICJDTUtJQUwwOVVXIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJLaXRvaSBCYXkiID0gYygiQ01XRVNBOTNVVyIsICJDTUtJVEIwOVVXIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJLaXpodXlhayBSaXZlciIgPSBjKCJDSEtJWjkyVVciLCAiQ01LSVpIMDlVVyIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiS3VqdWxpayBCYXkiID0gYygiQ01XRVNLOTNVVyIsICJDTUtVSlVORjA5VVciKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxpdHRsZSBKb2huIExhZ29vbiIgPSBjKCJDSExJSjkyVVciLCAiQ01MSUowOVVXIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQb3J0YWdlIENyZWVrIiA9IGMoIkNNV0VTSjkzVVciLCAiQ01QT1JUQzA4VVciKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlJ1c3NlbGwgQ3JlZWsiID0gYygiQ01SVVM5MlVXIiwgIkNNUlVTOTNVVyIsICJDTVJVUzA5VVciKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlJ1c3NpYW4gUml2ZXIiID0gYygiQ01SVVNTSTA3VVciLCAiQ01SVVNTSTA5VVciKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNhbmR5IENvdmUiID0gYygiQ01TQU5DOTZVVyIsICJDTVNBTkMwOVVXIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTdGVwb3ZhayBCYXkiID0gYygiQ01TVEU5MlVXIiwgIkNNU1RFMDlVVyIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVWdhbmlrIFJpdmVyIiA9IGMoIkNIVUdBOTJVVyIsICJDTVVHQU4wOVVXIikNCikNCnNhdmVfb2JqZWN0cygidGVtcG9yYWxfcG9vbGluZ19XQVNTSVAiLCAiLi4vMjAxOC9PYmplY3RzLyIpDQoNCiMgdmVyaWZ5IHRoYXQgYWxsIHNpbGx5cyBhcmUgaW4gY29sbGVjdGlvbnNfODgNCnNldGRpZmYodW5saXN0KHRlbXBvcmFsX3Bvb2xpbmdfV0FTU0lQKSwgY29sbGVjdGlvbnNfODgpDQpgYGANCg0KTm93IHRoYXQgd2UgaGF2ZSBvdXIgbGlzdCBvZiBXQVNTSVAgcG9wdWxhdGlvbnMgdG8gcG9vbCwgbGV0J3Mgc2VlIGhvdyB0aGV5IGRvIGluIEZpc2hlcidzIHRlc3QuDQpgYGB7ciB0ZW1wb3JhbF9wb29saW5nX1dBU1NJUF9maXNoZXJzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KdGVtcG9yYWxfcG9vbGluZ19XQVNTSVBfcmVzdWx0cyA8LSBGaXNoZXJzVGVzdC5HQ0woZnJlcSA9IGNvbGxlY3Rpb25zXzg4X2FsbGVsZV9mcmVxLCBsb2NpID0gbG9jaTk2LCB0ZXN0cyA9IHRlbXBvcmFsX3Bvb2xpbmdfV0FTU0lQKQ0Kc2F2ZV9vYmplY3RzKCJ0ZW1wb3JhbF9wb29saW5nX1dBU1NJUF9yZXN1bHRzIiwgIi4uLzIwMTgvT2JqZWN0cy8iKQ0KDQojIG92ZXJhbGwgbG9jaSBwLXZhbHVlcw0KdGVtcG9yYWxfcG9vbGluZ19XQVNTSVBfcmVzdWx0cyRPdmVyYWxsUmVzdWx0cyAlPiUgDQogIGFzX3RpYmJsZShyb3duYW1lcyA9ICJwb3AiKSAlPiUgDQogIGFycmFuZ2Uob3ZlcmFsbCkNCmBgYA0KDQpMb29rcyBnb29kIGVub3VnaCB0byBtZSwgYWxzbyBjb2luY2lkZXMgd2l0aCBXQVNTSVAsIHNvIHRoYXQgaXMgZ29vZCBuZXdzLiBOb3cgb24gdG8gY2hlY2sgQmFybGluZy4NCg0KIyMgQmFybGluZw0KDQpUZXN0IGFsbCBwb3NzaWJsZSBwYWlyd2lzZSBjb21iaW5hdGlvbnMgb2YgQmFybGluZyBzYW1wbGVzDQpgYGB7ciBiYXJsaW5nX3Bvb2xpbmcsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpiYXJsaW5nX3Bvb2xpbmcgPC0gY29tYm4oeCA9IGdyZXAocGF0dGVybiA9ICJCQVJMIiwgeCA9IGNvbGxlY3Rpb25zXzg4LCB2YWx1ZSA9IFRSVUUpLCBtID0gMiwgc2ltcGxpZnkgPSBGQUxTRSkNCnNhdmVfb2JqZWN0cygidGVtcG9yYWxfcG9vbGluZ19XQVNTSVAiLCAiLi4vMjAxOC9PYmplY3RzLyIpDQoNCmJhcmxpbmdfcG9vbGluZ19yZXN1bHRzIDwtIEZpc2hlcnNUZXN0LkdDTChmcmVxID0gY29sbGVjdGlvbnNfODhfYWxsZWxlX2ZyZXEsIGxvY2kgPSBsb2NpOTYsIHRlc3RzID0gYmFybGluZ19wb29saW5nKQ0Kc2F2ZV9vYmplY3RzKCJiYXJsaW5nX3Bvb2xpbmdfcmVzdWx0cyIsICIuLi8yMDE4L09iamVjdHMvIikNCg0KIyBvdmVyYWxsIGxvY2kgcC12YWx1ZXMNCmJhcmxpbmdfcG9vbGluZ19yZXN1bHRzJE92ZXJhbGxSZXN1bHRzICU+JSANCiAgYXNfdGliYmxlKHJvd25hbWVzID0gInBvcCIpICU+JSANCiAgYXJyYW5nZShvdmVyYWxsKQ0KYGBgDQoNCldoaWxlIGl0IGNlcnRhaW5seSBkb2VzIHNlZW0gbGlrZSB3ZSAiY291bGQiIHBvb2wgc29tZSBvZiB0aGUgQmFybGluZyBjb2xsZWN0aW9ucyBwZXIgb3VyIFdBU1NJUCBydWxlcywgSSB0aGluayBpdCBpcyBiZXN0IHRvIGxlYXZlIHRoZW0gYWxsIHNlcGFyYXRlIGZvciBub3cgZm9yIHBsb3R0aW5nIHB1cnBvc2VzLg0KDQojIyBGaW5hbCBwb29saW5nDQoNCkFjY2VwdCBhbGwgV0FTU0lQIHBvb2xpbmcgYW5kIG1vdmUgb24uDQpgYGB7ciBwb29sX3Blcl9XQVNTSVB9DQppbnZpc2libGUoDQogIGxhcHBseSh0ZW1wb3JhbF9wb29saW5nX1dBU1NJUCwgZnVuY3Rpb24ocG9wKSB7DQogICAgUG9vbENvbGxlY3Rpb25zLkdDTChjb2xsZWN0aW9ucyA9IHBvcCwgbG9jaSA9IGxvY2k5NiwgSURzID0gTlVMTCwgbmV3bmFtZSA9IHBhc3RlKHBvcCwgY29sbGFwc2UgPSAiLiIpKQ0KICB9ICkNCikNCmBgYA0KDQojIyBPcmRlcmVkIHBvcHVsYXRpb25zDQoNCk5lZWQgbmV3IGBzaWxseXZlY2Agd2l0aCBwb29sZWQgcG9wdWxhdGlvbnMuDQpgYGB7ciBwb3N0X3Bvb2xpbmd9DQpjb2xsZWN0aW9uc19wb3N0X3Bvb2xpbmcgPC0gYygNCiAgc2V0ZGlmZihzZXRkaWZmKGNvbGxlY3Rpb25zXzg4LCANCiAgICAgICAgICB1bmxpc3QodGVtcG9yYWxfcG9vbGluZ19XQVNTSVApKSwgICMgZ2V0IHNpbmdsZSBjb2xsZWN0aW9ucyBmcm9tIG5vbi1XQVNTSVAgcG9vbGluZw0KICBjKCJDTVZPTDkyVVciLCAiQ01WT0w5NlVXIiwgIkNNV0VTTTkzVVciLCAiQ01XRVNOOTNVVyIsICJDTVdFU0g5M1VXIikpLCAjIGRyb3AgdGhlc2Ugb2xkIGNvbGxlY3Rpb25zIHRoYXQgZGlkbid0IHBvb2wNCiAgc2FwcGx5KHRlbXBvcmFsX3Bvb2xpbmdfV0FTU0lQLCBmdW5jdGlvbihwb3ApIHsNCiAgICBwYXN0ZShwb3AsIGNvbGxhcHNlID0gIi4iKSAgIyBhZGQgcG9vbGVkIFdBU1NJUA0KICB9KQ0KKQ0KDQpkaXIuY3JlYXRlKCIuLi8yMDE4L0dlbm90eXBlcy9vcmlnaW5hbF9zcGxpdF9wb3N0UUFfcG9zdHBvb2xpbmcvIikNCnNhdmVfc2lsbHlzKGNvbGxlY3Rpb25zX3Bvc3RfcG9vbGluZywgIi4uLzIwMTgvR2Vub3R5cGVzL29yaWdpbmFsX3NwbGl0X3Bvc3RRQV9wb3N0cG9vbGluZy8iKQ0KYGBgDQoNCk5vdyBuZWVkIHRvIGpvaW4gdXAgdGhlc2UgcG9zdCBwb29saW5nIGNvbGxlY3Rpb25zIChwb3B1bGF0aW9ucykgd2l0aCB0aGUgcGFpcmVkIE9jZWFuQUsgZGF0YSBmcm9tIGBjb2xsZWN0aW9uc184OV9pbmZvYCBhbmQgZ2V0IGluIGdlb2dyYXBoaWNhbCBvcmRlci4NCg0KQWRkIG5ldyBncm91cGluZyB2YXJpYWJsZSBmb3I6ICANCiAgKiBTb3V0aCBQZW5pbnN1bGENCiAgKiBDaGlnbmlrDQogICogS29kaWFrIE1haW5sYW5kDQogICogS29kaWFrDQogICogU3R1cmdlb24vS2l0b2kNCiAgKiBCYXJsaW5nIFJpdmVyDQogICogMjAxNyBDb2xsZWN0aW9ucw0KDQpgYGB7ciBwb3N0X3Bvb2xpbmdfdGFibGUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpwb3B1bGF0aW9uc182M19pbmZvIDwtIHRpYmJsZShwb3AgPSBjb2xsZWN0aW9uc19wb3N0X3Bvb2xpbmcpICU+JSANCiAgbXV0YXRlKG4gPSBzYXBwbHkoY29sbGVjdGlvbnNfcG9zdF9wb29saW5nLCBmdW5jdGlvbih4KSB7Z2V0KHBhc3RlMCh4LCAiLmdjbCIpKSRufSApKSAlPiUgICMgZ2V0IGZpbmFsIHNhbXBsZSBzaXplcw0KICBtdXRhdGUocG9wX25vX1VXID0gc3RyX3JlbW92ZV9hbGwocG9wLCAiVVciKSkgJT4lICAjIHJlbW92ZSBVVyBleHRlbnNpb24NCiAgbXV0YXRlKHBvcF9ub19VVyA9IGRwbHlyOjpyZWNvZGUocG9wX25vX1VXLCAhISFsaXN0KCJDTUJBUkxSMTVFIiA9ICJDTUJBUkxSMTUiLCAiQ01CQVJMUjE1TSIgPSAiQ01CQVJMUjE1IiwgIkNNQkFSTFIxNUwiID0gIkNNQkFSTFIxNSIpKSkgJT4lICAjIHJlbW92ZSBFLCBNLCBMIGV4dGVuc2lvbiBmb3IgQmFybGluZyAyMDE1IGZvciBqb2luaW5nDQogIHNlcGFyYXRlKHBvcF9ub19VVywgYygiY29sMSIsICJjb2wyIiwgImNvbDMiKSwgc2VwID0gIlxcLiIsIHJlbW92ZSA9IFRSVUUpICU+JSAgIyBzZXBhcmF0ZSBzaWxseXMgdG8gam9pbiBkYXRlcw0KICBsZWZ0X2pvaW4oc2VsZWN0KGNvbGxlY3Rpb25zXzg5X2luZm8sIGBTaWxseSBDb2RlYCwgYENvbGxlY3Rpb24gRGF0ZWApLCBieSA9IGMoImNvbDEiID0gIlNpbGx5IENvZGUiKSkgJT4lICAjIGdldCBkYXRlIDENCiAgbGVmdF9qb2luKHNlbGVjdChjb2xsZWN0aW9uc184OV9pbmZvLCBgU2lsbHkgQ29kZWAsIGBDb2xsZWN0aW9uIERhdGVgKSwgYnkgPSBjKCJjb2wyIiA9ICJTaWxseSBDb2RlIikpICU+JSAgIyBnZXQgZGF0ZSAyDQogIGxlZnRfam9pbihzZWxlY3QoY29sbGVjdGlvbnNfODlfaW5mbywgYFNpbGx5IENvZGVgLCBgQ29sbGVjdGlvbiBEYXRlYCksIGJ5ID0gYygiY29sMyIgPSAiU2lsbHkgQ29kZSIpKSAlPiUgICMgZ2V0IGRhdGUgMw0KICByZW5hbWUoIkNvbGxlY3Rpb24gRGF0ZSAxIiA9ICJDb2xsZWN0aW9uIERhdGUueCIsICJDb2xsZWN0aW9uIERhdGUgMiIgPSAiQ29sbGVjdGlvbiBEYXRlLnkiLCAiQ29sbGVjdGlvbiBEYXRlIDMiID0gIkNvbGxlY3Rpb24gRGF0ZSIpICU+JSAgIyByZW5hbWUgZGF0ZXMNCiAgbXV0YXRlKGBDb2xsZWN0aW9uIERhdGUgMWAgPSBzdHJfcmVwbGFjZShgQ29sbGVjdGlvbiBEYXRlIDFgLCAiMS8xLzE5OTIiLCAiMTk5MiIpKSAlPiUgICMgQ01aQUMwOSBoYXMgYm9ndXMgZGF0ZQ0KICBtdXRhdGUoY29sID0gaWZlbHNlKGlzLm5hKGNvbDMpLCBpZmVsc2UoaXMubmEoY29sMiksIGNvbDEsIGNvbDIpLCBjb2wzKSkgJT4lICAjIGdldCBsYXRlc3QgY29sbGVjdGlvbiBmcm9tIGVhY2ggcG9wDQogIGxlZnRfam9pbihzZWxlY3QoY29sbGVjdGlvbnNfODlfaW5mbywgYFNpbGx5IENvZGVgLCBRdWFkcmFudCwgY29sb3IsIExvY2F0aW9uLCBMYXRpdHVkZSwgTG9uZ2l0dWRlKSwgYnkgPSBjKCJjb2wiID0gIlNpbGx5IENvZGUiKSkgJT4lICAjIGpvaW4gT2NlYW5BSyBiYXNlZCBvbiBsYXRlc3QgY29sbGVjdGlvbiBmcm9tIGVhY2ggcG9wDQogIG11dGF0ZShHcm91cCA9IGNhc2Vfd2hlbihRdWFkcmFudCA9PSAiUGVuaW5zdWxhIC0gU291dGgiIH4gIlNvdXRoIFBlbmluc3VsYSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBRdWFkcmFudCA9PSAiQ2hpZ25payIgfiAiQ2hpZ25payIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBRdWFkcmFudCA9PSAiS29kaWFrIE1haW5sYW5kIiB+ICJLb2RpYWsgTWFpbmxhbmQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9wICVpbiUgYygiQ01QQVVMMTUiLCAiQ01TVFUwOVVXIiwgIkNNV0VTQTkzVVcuQ01LSVRCMDlVVyIpIH4gIlN0dXJnZW9uL0tpdG9pIEJheSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBwb3AgJWluJSBjKCJDTUJBUkwwOVVXIiwgIkNNQkFSTFIxNUUiLCAiQ01CQVJMUjE1TSIsICJDTUJBUkxSMTVMIikgfiAiQmFybGluZyBCYXkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9wICVpbiUgYygiQ01OQVRBMTciLCAiQ01LSUFWMTciLCAiQ01CQVJMMTciKSB+ICIyMDE3IENvbGxlY3Rpb25zIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiS29kaWFrIikpICU+JSAgIyBjcmVhdGUgZ3JvdXAgZm9yIGdyb3VwdmVjDQogIGRwbHlyOjpzZWxlY3QocG9wLCBMb2NhdGlvbiwgYENvbGxlY3Rpb24gRGF0ZSAxYCwgYENvbGxlY3Rpb24gRGF0ZSAyYCwgYENvbGxlY3Rpb24gRGF0ZSAzYCwgR3JvdXAsIFF1YWRyYW50LCBuLCBMYXRpdHVkZSwgTG9uZ2l0dWRlLCBjb2xvcikgJT4lICAjIGtlZXAgY29sdW1ucw0KICBzZXBhcmF0ZShMb2NhdGlvbiwgYygiTG9jYXRpb24iLCAidHJhc2giKSwgc2VwID0gIiAtICIpICU+JSAgIyBzdGFuZGFyZGl6ZSBMb2NhdGlvbnMgcGFydCAxDQogIHNlcGFyYXRlKExvY2F0aW9uLCBjKCJMb2NhdGlvbiIsICJtb3JlX3RyYXNoIiksIHNlcCA9ICIgXFwoIikgJT4lICAjIHN0YW5kYXJkaXplIExvY2F0aW9ucyBwYXJ0IDINCiAgZHBseXI6OnNlbGVjdCgtdHJhc2gsIC1tb3JlX3RyYXNoKSAlPiUgICMgZHJvcCBib2d1cyBsb2NhdGlvbiBpbmZvDQogIG11dGF0ZShgQ29sbGVjdGlvbiBEYXRlIDFgID0gY2FzZV93aGVuKHBvcCA9PSAiQ01CQVJMUjE1TSIgfiAiOC8zLzIwMTUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb3AgPT0gIkNNQkFSTFIxNUwiIH4gIjkvMTEvMjAxNSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBgQ29sbGVjdGlvbiBEYXRlIDFgKSkgJT4lICAjIGZpeCBCYXJsaW5nIDIwMTUgZGF0ZXMNCiAgbXV0YXRlKE1vbnRoID0gbW9udGgobWR5KGBDb2xsZWN0aW9uIERhdGUgMWApLCBsYWJlbCA9IFRSVUUpKSAlPiUgIyAgZXh0cmFjdCBtb250aA0KICBkcGx5cjo6c2VsZWN0KHBvcCwgTG9jYXRpb24sIGBDb2xsZWN0aW9uIERhdGUgMWAsIGBDb2xsZWN0aW9uIERhdGUgMmAsIGBDb2xsZWN0aW9uIERhdGUgM2AsIE1vbnRoLCBHcm91cCwgUXVhZHJhbnQsIG4sIExhdGl0dWRlLCBMb25naXR1ZGUsIGNvbG9yKSAgIyBrZWVwIGNvbHVtbnMNCg0KDQpgYGANCg0KQ3JlYXRlIGEgbGVhZmxldCBtYXAgdG8gZGV0ZXJtaW5lIG1hcCBvcmRlciBmb3IgcG9wdWxhdGlvbnMuDQpgYGB7ciBwb3B1bGF0aW9uX21hcH0NCnBvcHVsYXRpb25zXzYzX2luZm8gPC0gcG9wdWxhdGlvbnNfNjNfaW5mbyAlPiUgDQogIG11dGF0ZShjb2xvciA9IGNhc2Vfd2hlbihHcm91cCA9PSAiU291dGggUGVuaW5zdWxhIiB+ICJyZWQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgR3JvdXAgPT0gIkNoaWduaWsiIH4gImRhcmtyZWQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgR3JvdXAgPT0gIktvZGlhayBNYWlubGFuZCIgfiAib3JhbmdlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIEdyb3VwID09ICJLb2RpYWsiIH4gImdyZWVuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIEdyb3VwID09ICJTdHVyZ2Vvbi9LaXRvaSBCYXkiIH4gImJsdWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgR3JvdXAgPT0gIkJhcmxpbmcgQmF5IiB+ICJwdXJwbGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgR3JvdXAgPT0gIjIwMTcgQ29sbGVjdGlvbnMiIH4gImRhcmtwdXJwbGUiKSkNCg0KY29sb3JzXzcgPC0gYygicmVkIiwgImRhcmtyZWQiLCAib3JhbmdlIiwgImJsdWUiLCAiZ3JlZW4iLCAicHVycGxlIiwgInZpb2xldCIpDQpzYXZlX29iamVjdHMoImNvbG9yc183IiwgIi4uLzIwMTgvT2JqZWN0cy8iKQ0KDQppY29ucyA8LSBhd2Vzb21lSWNvbnMoaWNvbiA9ICdjaXJjbGUnLCBpY29uQ29sb3IgPSAnYmxhY2snLCBsaWJyYXJ5ID0gJ2lvbicsIG1hcmtlckNvbG9yID0gcG9wdWxhdGlvbnNfNjNfaW5mbyRjb2xvcikNCg0KcG9wdWxhdGlvbnNfNjNfaW5mbyAlPiUgDQogIGxlYWZsZXQod2lkdGggPSAiMTAwJSIpICU+JSANCiAgYWRkVGlsZXMoKSAlPiUgDQogIGFkZEF3ZXNvbWVNYXJrZXJzKH4gTG9uZ2l0dWRlLCB+IExhdGl0dWRlLCBpY29uID0gaWNvbnMsIGxhYmVsID0gfiBwb3AsIGxhYmVsT3B0aW9ucyA9IGxhYmVsT3B0aW9ucyhub0hpZGUgPSBUUlVFLCBkaXJlY3Rpb24gPSAiYXV0byIpKQ0KYGBgDQoNClNhdmUgZ2VvZ3JhcGh5IG9yZGVyZWQgcG9wdWxhdGlvbiB2ZWN0b3IuICANCg0KYGBge3IgcG9wdWxhdGlvbnNfNjN9DQpwb3B1bGF0aW9uc182MyA8LSByZWFkX2NzdigiLi4vMjAxOC9wb3B1bGF0aW9uc182My5jc3YiKQ0KDQpwb3B1bGF0aW9uc182M19pbmZvIDwtIHBvcHVsYXRpb25zXzYzX2luZm8gJT4lIA0KICBsZWZ0X2pvaW4ocG9wdWxhdGlvbnNfNjMsIGJ5ID0gInBvcCIpICU+JSANCiAgc2VsZWN0KHBvcF9ubywgbWFwX25vLCBwb3AsIExvY2F0aW9uLCBgQ29sbGVjdGlvbiBEYXRlIDFgLCBgQ29sbGVjdGlvbiBEYXRlIDJgLCBgQ29sbGVjdGlvbiBEYXRlIDNgLCBNb250aCwgR3JvdXAsIFF1YWRyYW50LCBuLCBMYXRpdHVkZSwgTG9uZ2l0dWRlLCBjb2xvcikgJT4lIA0KICBhcnJhbmdlKHBvcF9ubykNCg0Kd3JpdGVfY3N2KHBvcHVsYXRpb25zXzYzX2luZm8sICIuLi8yMDE4L1RhYmxlcy9wb3B1bGF0aW9uc182M19pbmZvLmNzdiIpDQoNCnBvcHVsYXRpb25zXzYzIDwtIHBvcHVsYXRpb25zXzYzJHBvcA0KZ3JvdXBzXzcgPC0gdW5pcXVlKHBvcHVsYXRpb25zXzYzX2luZm8kR3JvdXApDQpncm91cHZlY183IDwtIG1hdGNoKHBvcHVsYXRpb25zXzYzX2luZm8kR3JvdXAsIGdyb3Vwc183KQ0Kc2F2ZV9vYmplY3RzKGMoInBvcHVsYXRpb25zXzYzIiwgInBvcHVsYXRpb25zXzYzX2luZm8iLCAiZ3JvdXBzXzciLCAiZ3JvdXB2ZWNfNyIpLCAiLi4vMjAxOC9PYmplY3RzLyIpDQpgYGANCg0KDQojIyMgRmluYWwgbWFwDQoNCk1ha2UgbWFwIHdpdGggdGhlIGNvcnJlY3QgbWFwIG51bWJlcnMgdG8gZG91YmxlIGNoZWNrLg0KYGBge3IgcG9wdWxhdGlvbl9tYXBfbnVtYmVyc30NCmljb25zIDwtIGF3ZXNvbWVJY29ucyhpY29uID0gJ2VnZycsIGljb25Db2xvciA9ICd0cmFuc3BhcmVudCcsIGxpYnJhcnkgPSAnaW9uJywgbWFya2VyQ29sb3IgPSBwb3B1bGF0aW9uc182M19pbmZvJGNvbG9yKQ0KDQpwb3B1bGF0aW9uc182M19pbmZvICU+JSANCiAgbGVhZmxldCh3aWR0aCA9ICIxMDAlIikgJT4lIA0KICBhZGRUaWxlcygpICU+JSANCiAgYWRkQXdlc29tZU1hcmtlcnMofiBMb25naXR1ZGUsIH4gTGF0aXR1ZGUsIGljb24gPSBpY29ucywgbGFiZWwgPSB+IGFzLmNoYXJhY3RlcihtYXBfbm8pLCBwb3B1cCA9IH4gTG9jYXRpb24sIGxhYmVsT3B0aW9ucyA9IGxhYmVsT3B0aW9ucyhub0hpZGUgPSBUUlVFLCB0ZXh0T25seSA9IFRSVUUsIGRpcmVjdGlvbiA9ICJ0b3AiKSkNCmBgYA0KDQojIENoZWNrICpIV0UqIC0gcG9wdWxhdGlvbnMNCg0KV3JpdGUgb3V0IGEgKkdlbmVwb3AqIGZpbGUgdG8gY2hlY2sgSFdFIHdpdGhpbiBwb3B1bGF0aW9ucy4NCmBgYHtyIHdyaXRlX2dlbmVwb3BfcG9wfQ0KZ2NsMkdlbmVwb3AuR0NMKHNpbGx5dmVjID0gcG9wdWxhdGlvbnNfNjMsIGxvY2kgPSBsb2NpOTYsIHBhdGggPSAiLi4vMjAxOC9HZW5lcG9wL3BvcHVsYXRpb25zXzYzLmdlbiIsIFZpYWxOdW1zID0gVFJVRSkNCmBgYA0KDQpDYWxjdWxhdGUgSFdFIHVzaW5nIHRoZSAqZ2VuZXBvcCogcGFja2FnZSBbbGlua10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2dlbmVwb3AvaW5kZXguaHRtbCkuDQpgYGB7ciBwb3B1bGF0aW9uc182M19od2V9DQp0ZXN0X0hXKGlucHV0RmlsZSA9ICIuLi8yMDE4L0dlbmVwb3AvcG9wdWxhdGlvbnNfNjMuZ2VuIiwgb3V0cHV0RmlsZSA9ICIuLi8yMDE4L0dlbmVwb3AvcG9wdWxhdGlvbnNfNjMudHh0LlAiKQ0KYGBgDQoNCiMjIFN1bW1hcnkgdGFibGUNClJlYWQgaW4gcmVzdWx0cyBhbmQgc2F2ZSBzdW1tYXJ5IEhXRSBwLXZhbHVlcy4NCmBgYHtyIGh3ZV9yZXN1bHRzX3BvcH0NCmh3ZV9wb3B1bGF0aW9uc182MyA8LSBSZWFkR2VuZXBvcEhXRS5HQ0woZmlsZSA9ICIuLi8yMDE4L0dlbmVwb3AvcG9wdWxhdGlvbnNfNjMudHh0LlAiLCBzaWxseXZlYyA9IHBvcHVsYXRpb25zXzYzKQ0KKGh3ZV9zdW1tYXJ5X3BvcHVsYXRpb25zXzYzIDwtIGh3ZV9wb3B1bGF0aW9uc182MyRTdW1tYXJ5UFZhbHVlcyAlPiUgDQogIGFzX3RpYmJsZShyb3duYW1lcyA9ICJsb2N1cyIpKQ0Kd3JpdGVfY3N2KHggPSBod2Vfc3VtbWFyeV9wb3B1bGF0aW9uc182MywgIi4uLzIwMTgvVGFibGVzL2h3ZV9zdW1tYXJ5X3BvcHVsYXRpb25zXzYzLmNzdiIpDQpgYGANCg0KIyMjIFBvcHVsYXRpb25zIG91dCBvZiBIV1ANCldoYXQgZG8gb3ZlcmFsbC1sb2NpIHAtdmFsdWVzIGxvb2sgbGlrZSBmb3IgY29sbGVjdGlvbnM/DQpgYGB7ciBod2Vfb3ZlcmFsbF9sb2NpX3BvcH0NCmh3ZV9zdW1tYXJ5X3BvcHVsYXRpb25zXzYzICU+JSANCiAgZ2F0aGVyKHNpbGx5LCBwLCAtbG9jdXMpICU+JQ0KICBmaWx0ZXIobG9jdXMgPT0gIk92ZXJhbGwgTG9jaSIpICU+JSANCiAgYXJyYW5nZShwKQ0KYGBgDQoNCkxvb2tzIHByZXR0eSBnb29kLCBub3RoaW5nIG1ham9yIHRvIHdvcnJ5IGFvYnV0LiBPbiB0byBGc3QhDQoNCiMgQ29tYmluZSBsb2NpDQoNClBsYW5uaW5nIHRvIHVzZSBXQVNTSVAgbG9jdXMgaW5mb3JtYXRpb24gKEFERiZHIFNQMTItMjYpOiAgDQoNCiAgKiBDb21iaW5nIDMgaGFwbG9pZCBsb2NpIChtaXRvY2hvbmRyaWFsKQ0KICAgIC0gT2tlX0NyMzANCiAgICAtIE9rZV9DcjM4Ng0KICAgIC0gT2tlX05EMy02OQ0KICAqIENvbWJpbmUgMiBsaW5rZWQgZGlwbG9pZCBsb2NpIChudWNsZWFyKQ0KICAgIC0gT2tlX1UxMDIxLTEwMg0KICAgIC0gT2tlX1UxMDIyLTEzOQ0KICAqIERyb3AgMiBkaXBsb2lkIGxvY2kgKG51Y2xlYXIpIGR1ZSB0byBsaW5rYWdlDQogICAgLSBPa2VfZ2RoMS02Mg0KICAgIC0gT2tlX3BnYXAtOTINCg0KYGBge3IgY29tYmluZV9sb2NpfQ0KbWl0b19jb21iaW5lIDwtIG5hbWVzKHdoaWNoKExvY3VzQ29udHJvbCRwbG9pZHkgPT0gMSkpDQpudWNsZWFyX2NvbWJpbmUgPC0gYygiT2tlX1UxMDIxLTEwMiIsICJPa2VfVTEwMjItMTM5IikNCm51Y2xlYXJfZHJvcCA8LSBjKCJPa2VfZ2RoMS02MiIsICJPa2VfcGdhcC05MiIpDQoNCkNvbWJpbmVMb2NpLkdDTChzaWxseXZlYyA9IHBvcHVsYXRpb25zXzYzLCBtYXJrZXJzZXQgPSBudWNsZWFyX2NvbWJpbmUsIHVwZGF0ZSA9IFRSVUUsIGRlbGltID0gIi4iKQ0KQ29tYmluZUxvY2kuR0NMKHNpbGx5dmVjID0gcG9wdWxhdGlvbnNfNjMsIG1hcmtlcnNldCA9IG1pdG9fY29tYmluZSwgdXBkYXRlID0gVFJVRSwgZGVsaW0gPSAiLiIpDQpkaXIuY3JlYXRlKCIuLi8yMDE4L0dlbm90eXBlcy9vcmlnaW5hbF9zcGxpdF9wb3N0UUFfcG9zdHBvb2xpbmdfY29tYmluZWxvY2kvIikNCnNhdmVfc2lsbHlzKHBvcHVsYXRpb25zXzYzLCAiLi4vMjAxOC9HZW5vdHlwZXMvb3JpZ2luYWxfc3BsaXRfcG9zdFFBX3Bvc3Rwb29saW5nX2NvbWJpbmVsb2NpLyIpDQoNCmxvY2k5MSA8LSBjKA0KICBzZXRkaWZmKGxvY2k5NiwgDQogICAgICAgICAgYyhudWNsZWFyX2Ryb3AsIG1pdG9fY29tYmluZSwgbnVjbGVhcl9jb21iaW5lKSksICAjIGRyb3AgbGlua2VkIG1hcmtlcnMgYW5kIHNpbmdsZSBjb21iaW5lZA0KICBwYXN0ZShudWNsZWFyX2NvbWJpbmUsIGNvbGxhcHNlID0gIi4iKSwgcGFzdGUobWl0b19jb21iaW5lLCBjb2xsYXBzZSA9ICIuIikpICAjIGFkZCBjb21iaW5lZA0KYGBgDQoNCiMgQWxsZWxlIGZyZXF1ZW5jeSBwbG90cw0KDQpDYWxjdWxhdGUgYWxsZWxlIGZyZXF1ZW5jaWVzLg0KYGBge3IgYWxsZWxlX2ZyZXF1ZW5jaWVzfQ0KZGlyLmNyZWF0ZSgiLi4vMjAxOC9GcmVxUGxvdHMiKQ0KYWxsZWxlX2ZyZXEgPC0gRnJlcUZpc1Bsb3Q0U05Qcy5HQ0woc2lsbHl2ZWMgPSBwb3B1bGF0aW9uc182MywgbG9jaSA9IGxvY2k5NiwgZ3JvdXB2ZWMgPSBncm91cHZlY183LCBncm91cGNvbCA9IGNvbG9yc183LCBmaWxlID0gIi4uLzIwMTgvRnJlcVBsb3RzL2FsbGVsZV9mcmVxX3BvcHVsYXRpb25zXzYzX2xvY2k5Ni5wZGYiKQ0KYGBgDQoNCiMgRnN0DQoNCiMjIENhbGN1bGF0ZQ0KTm93IHRoYXQgd2UgaGF2ZSBvdXIgZmluYWwgcG9zdC1RQSwgcG9zdC1wb29saW5nIGdlbm90eXBlcywgdGltZSB0byBjYWxjdWxhdGUgRnN0IGJldHdlZW4gYWxsIG9mIG91ciBwb3B1bGF0aW9ucy4NCmBgYHtyIEZzdF90cmVlfQ0KZGlyLmNyZWF0ZSgiLi4vMjAxOC9GU1RBVCIpDQpGc3RfdHJlZV9wb3B1bGF0aW9uc182M19sb2NpOTEgPC0gUGFpcndpc2VGc3RUcmVlLkdDTChzaWxseXZlYyA9IHBvcHVsYXRpb25zXzYzLCBsb2NpID0gbG9jaTkxLCBkaXIgPSAiLi4vMjAxOC9GU1RBVCIsIG5ib290cyA9IDEwMDAsIG5jb3JlcyA9IDQsIHJldHVybmJvb3RzdHJhcEZzdCA9IEZBTFNFKQ0KYGBgDQoNCiMjIEhlYXRtYXAgb2YgRnN0DQpgYGB7ciBmc3RfaGVhdG1hcCwgZmlnLndpZHRoPTExLjUsIGZpZy5oZWlnaHQ9MTB9DQpwYWlyd2lzZV9mc3QgPC0gRnN0X3RyZWVfcG9wdWxhdGlvbnNfNjNfbG9jaTkxJFBhaXJ3aXNlRnN0DQp3cml0ZV9jc3YoYXNfZGF0YV9mcmFtZShwYWlyd2lzZV9mc3QsIHJvd25hbWVzID0gInBvcCIpLCAiLi4vMjAxOC9UYWJsZXMvcGFpcndpc2VfZnN0X3BvcHVsYXRpb25zXzYzLmNzdiIpDQpzYXZlX29iamVjdHMoInBhaXJ3aXNlX2ZzdCIsICIuLi8yMDE4L09iamVjdHMvIikNCg0KZ2V0X2xvd2VyX3RyaSA8LSBmdW5jdGlvbihtYXQpIHsNCiAgbWF0W3VwcGVyLnRyaShtYXQpXSA8LSBOQQ0KICByZXR1cm4obWF0KQ0KfQ0KDQpnZXRfbG93ZXJfdHJpKHBhaXJ3aXNlX2ZzdCkgJT4lIA0KICBhc190aWJibGUocm93bmFtZXMgPSAicG9wMSIpICU+JQ0KICBtdXRhdGUocG9wMSA9IGZhY3Rvcihwb3AxLCBwb3B1bGF0aW9uc182MykpICU+JSANCiAgZ2F0aGVyKHBvcDIsIGZzdCwgLXBvcDEsIG5hLnJtID0gVFJVRSwgZmFjdG9yX2tleSA9IFRSVUUpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gcG9wMSwgeSA9IHBvcDIsIGZpbGwgPSBmc3QpKSArDQogIGdlb21fdGlsZSgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0ID0gMSkpICsNCiAgZ2d0aXRsZSgiUGFpcndpc2UgRnN0IC0gNjMgUG9wdWxhdGlvbnMsIDkxIExvY2kiKQ0KYGBgDQoNCiMjIE1EUw0KDQojIyMgQWxsIHBvcHVsYXRpb25zDQoNCk1ha2UgYW4gTURTIG9mIHRoZSBGc3QgZGF0YSBmb3IgY29tcGFyaXNvbiB0byBBbmR5J3Mgd29yayBiYWNrIGluIDIwMTUuDQpgYGB7ciBmc3RfbWRzX2FsbCwgd2FybmluZz1GQUxTRSwgZmlnLndpZHRoPTExLjUsIGZpZy5oZWlnaHQ9MTB9DQpkaXN0ID0gcGFpcndpc2VfZnN0DQpwb3B2ZWMgPSAxOjYzDQpncm91cHN2ZWMgPSAxOjcNCmNvbHZlYyA9IG1hdGNoKGNvbG9yc183W2dyb3VwdmVjXzddLCBjb2xvcnMoKSkNCmdyb3VwcyA9IGdyb3Vwc183W2dyb3Vwc3ZlY10NCmNvbHMgPSBjb2xvcnNfN1tncm91cHN2ZWNdDQptYWluID0gIiINCmxhYmVscyA9IFRSVUUNCmxvY05hbWVzID0gMTo2Mw0KYXhlcyA9IFRSVUUNCmJveCA9IFRSVUUNCmFkaiA9IGMoMS41LCAxLjUpDQpjZXggPSAxDQpzaXplID0gMS4zDQoNCiN+fn5+fn5+fg0KbmFtZXMgPC0gaWYobGFiZWxzPT1GKXtOVUxMfSBlbHNle2lmKGxvY05hbWVzPT1GKXtwb3B2ZWN9IGVsc2V7bG9jTmFtZXNbcG9wdmVjXX19DQp4eD1kaXN0W3BvcHZlYyxwb3B2ZWNdDQp4PWFzLnZlY3RvcihjbWRzY2FsZSh4eCxrPTMpWywxXSkNCnk9YXMudmVjdG9yKGNtZHNjYWxlKHh4LGs9MylbLDJdKQ0Kej0tYXMudmVjdG9yKGNtZHNjYWxlKHh4LGs9MylbLDNdKQ0KDQpwbG90M2QoeCx5LHorYWJzKHJhbmdlKHopWzFdKSxhc3BlY3Q9Rixjb2w9Y29sb3JzKClbY29sdmVjW3BvcHZlY11dLHNpemU9c2l6ZSx0eXBlPSdzJyxtYWluPW1haW4sYm94PWJveCxheGVzPWF4ZXMsdG9wPVQsY2V4PTEseGxhYj0nJyx5bGFiPScnLHpsYWI9JycseGxlbj0wLHlsZW49MCx6bGVuPTApDQoNCnBsb3QzZCh4LHkseithYnMocmFuZ2UoeilbMV0pLGFzcGVjdD1GLGNvbD0iYmxhY2siLHNpemU9Myx0eXBlPSdoJyxib3g9RixheGVzPUYsdG9wPVQsYWRkPVQseGxhYj0nJyx5bGFiPScnLHpsYWI9JycseGxlbj0wLHlsZW49MCx6bGVuPTApDQoNCmlmKGxhYmVscz09VCl7dGV4dHMzZCh4LHkseithYnMocmFuZ2UoeilbMV0pLGFkaj1hZGosdGV4dD1uYW1lcyxmb250PTEsY2V4PWNleCxhZGQ9VCx0b3A9VCxheGVzPUYseGxhYj0nJyx5bGFiPScnLHpsYWI9JycpfQ0KDQpwYXIzZCh3aW5kb3dSZWN0ID0gYygwLCAwLCAyMDAwLCAyMDAwKSkNCg0KbGVnZW5kM2QoInRvcHJpZ2h0IiwgbGVnZW5kID0gZ3JvdXBzLCBwY2ggPSAxNiwgY29sID0gY29scywgaW5zZXQgPSBjKDApLCBjZXggPSA1KQ0KDQpyZ2x3aWRnZXQoKQ0KYGBgDQoNCiMjIyBLb2RpYWsgcG9wdWxhdGlvbnMNCg0KTWFrZSBhbiBNRFMgb2YgdGhlIEZzdCBkYXRhIGZvciBqdXN0IEtvZGlhayBwb3B1bGF0aW9ucw0KDQpgYGB7ciBmc3RfbWRzX2tvZGlhaywgd2FybmluZz1GQUxTRSwgZmlnLndpZHRoPTExLjUsIGZpZy5oZWlnaHQ9MTB9DQpkaXN0ID0gcGFpcndpc2VfZnN0DQpwb3B2ZWMgPSAzMjo2Mw0KY29sdmVjID0gbWF0Y2goY29sb3JzXzdbZ3JvdXB2ZWNfN10sIGNvbG9ycygpKQ0KZ3JvdXBzID0gZ3JvdXBzXzdbNDo3XQ0KY29scyA9IGNvbG9yc183WzQ6N10NCm1haW4gPSAiIg0KbGFiZWxzID0gVFJVRQ0KbG9jTmFtZXMgPSAxOjYzDQpheGVzID0gVFJVRQ0KYm94ID0gVFJVRQ0KYWRqID0gYygxLjUsIDEuNSkNCmNleCA9IDENCnNpemUgPSAxLjMNCg0KI35+fn5+fn5+DQpuYW1lcyA8LSBpZihsYWJlbHM9PUYpe05VTEx9IGVsc2V7aWYobG9jTmFtZXM9PUYpe3BvcHZlY30gZWxzZXtsb2NOYW1lc1twb3B2ZWNdfX0NCnh4PWRpc3RbcG9wdmVjLHBvcHZlY10NCng9YXMudmVjdG9yKGNtZHNjYWxlKHh4LGs9MylbLDFdKQ0KeT1hcy52ZWN0b3IoY21kc2NhbGUoeHgsaz0zKVssMl0pDQp6PS1hcy52ZWN0b3IoY21kc2NhbGUoeHgsaz0zKVssM10pDQoNCnBsb3QzZCh4LHkseithYnMocmFuZ2UoeilbMV0pLGFzcGVjdD1GLGNvbD1jb2xvcnMoKVtjb2x2ZWNbcG9wdmVjXV0sc2l6ZT1zaXplLHR5cGU9J3MnLG1haW49bWFpbixib3g9Ym94LGF4ZXM9YXhlcyx0b3A9VCxjZXg9MSx4bGFiPScnLHlsYWI9JycsemxhYj0nJyx4bGVuPTAseWxlbj0wLHpsZW49MCkNCg0KcGxvdDNkKHgseSx6K2FicyhyYW5nZSh6KVsxXSksYXNwZWN0PUYsY29sPSJibGFjayIsc2l6ZT0zLHR5cGU9J2gnLGJveD1GLGF4ZXM9Rix0b3A9VCxhZGQ9VCx4bGFiPScnLHlsYWI9JycsemxhYj0nJyx4bGVuPTAseWxlbj0wLHpsZW49MCkNCg0KaWYobGFiZWxzPT1UKXt0ZXh0czNkKHgseSx6K2FicyhyYW5nZSh6KVsxXSksYWRqPWFkaix0ZXh0PW5hbWVzLGZvbnQ9MSxjZXg9Y2V4LGFkZD1ULHRvcD1ULGF4ZXM9Rix4bGFiPScnLHlsYWI9JycsemxhYj0nJyl9DQoNCnBhcjNkKHdpbmRvd1JlY3QgPSBjKDAsIDAsIDIwMDAsIDIwMDApKQ0KDQpsZWdlbmQzZCgidG9wcmlnaHQiLCBsZWdlbmQgPSBncm91cHMsIHBjaCA9IDE2LCBjb2wgPSBjb2xzLCBpbnNldCA9IGMoMCksIGNleCA9IDUpDQoNCnJnbHdpZGdldCgpDQpgYGANCg0KIyMjIEtvZGlhayBwb3B1bGF0aW9ucywgbm8gb3V0bGllcnMNCg0KUmVtb3ZlIFN0dXJnZW9uL0tpdG8gQmF5IHBvcHVsYXRpb25zLCBLYXJsdWsgTGFnb29uLCBHdWxsIENhcGUgTGFnb29uLCBCaWcgU3VraG9pLCBhbmQgU2l0a2luYWsgSXNsYW5kIGFzIG91dGxpZXJzLg0KYGBge3IgZnN0X21kc19rb2RpYWtfbm9fb3V0bGllcnMsIHdhcm5pbmc9RkFMU0UsIGZpZy53aWR0aD0xMS41LCBmaWcuaGVpZ2h0PTEwfQ0KZGlzdCA9IHBhaXJ3aXNlX2ZzdA0KcG9wdmVjID0gcG9wdWxhdGlvbnNfNjNfaW5mbyAlPiUgDQogIG11dGF0ZShwb3Bfbm8gPSAxOjYzKSAlPiUgDQogIGZpbHRlcihRdWFkcmFudCA9PSAiS29kaWFrL0Fmb2duYWsgSXNsYW5kcyIpICU+JSANCiAgZmlsdGVyKEdyb3VwICE9ICJTdHVyZ2Vvbi9LaXRvaSBCYXkiKSAlPiUgDQogIGZpbHRlcighTG9jYXRpb24gJWluJSBjKCJLYXJsdWsgTGFnb29uIiwgIkd1bGwgQ2FwZSBMYWdvb24iLCAiQmlnIFN1a2hvaSIsICJTaXRraW5hayBJc2xhbmQiKSkgJT4lIA0KICBwdWxsKHBvcF9ubykNCmdyb3Vwc3ZlYyA9IDU6Nw0KY29sdmVjID0gbWF0Y2goY29sb3JzXzdbZ3JvdXB2ZWNfN10sIGNvbG9ycygpKQ0KZ3JvdXBzID0gZ3JvdXBzXzdbZ3JvdXBzdmVjXQ0KY29scyA9IGNvbG9yc183W2dyb3Vwc3ZlY10NCm1haW4gPSAiIg0KbGFiZWxzID0gVFJVRQ0KbG9jTmFtZXMgPSAxOjYzDQpheGVzID0gVFJVRQ0KYm94ID0gVFJVRQ0KYWRqID0gYygxLjUsIDEuNSkNCmNleCA9IDENCnNpemUgPSAxLjMNCg0KI35+fn5+fn5+DQpuYW1lcyA8LSBpZihsYWJlbHM9PUYpe05VTEx9IGVsc2V7aWYobG9jTmFtZXM9PUYpe3BvcHZlY30gZWxzZXtsb2NOYW1lc1twb3B2ZWNdfX0NCnh4PWRpc3RbcG9wdmVjLHBvcHZlY10NCng9YXMudmVjdG9yKGNtZHNjYWxlKHh4LGs9MylbLDFdKQ0KeT1hcy52ZWN0b3IoY21kc2NhbGUoeHgsaz0zKVssMl0pDQp6PS1hcy52ZWN0b3IoY21kc2NhbGUoeHgsaz0zKVssM10pDQoNCnBsb3QzZCh4LHkseithYnMocmFuZ2UoeilbMV0pLGFzcGVjdD1GLGNvbD1jb2xvcnMoKVtjb2x2ZWNbcG9wdmVjXV0sc2l6ZT1zaXplLHR5cGU9J3MnLG1haW49bWFpbixib3g9Ym94LGF4ZXM9YXhlcyx0b3A9VCxjZXg9MSx4bGFiPScnLHlsYWI9JycsemxhYj0nJyx4bGVuPTAseWxlbj0wLHpsZW49MCkNCg0KcGxvdDNkKHgseSx6K2FicyhyYW5nZSh6KVsxXSksYXNwZWN0PUYsY29sPSJibGFjayIsc2l6ZT0zLHR5cGU9J2gnLGJveD1GLGF4ZXM9Rix0b3A9VCxhZGQ9VCx4bGFiPScnLHlsYWI9JycsemxhYj0nJyx4bGVuPTAseWxlbj0wLHpsZW49MCkNCg0KaWYobGFiZWxzPT1UKXt0ZXh0czNkKHgseSx6K2FicyhyYW5nZSh6KVsxXSksYWRqPWFkaix0ZXh0PW5hbWVzLGZvbnQ9MSxjZXg9Y2V4LGFkZD1ULHRvcD1ULGF4ZXM9Rix4bGFiPScnLHlsYWI9JycsemxhYj0nJyl9DQoNCnBhcjNkKHdpbmRvd1JlY3QgPSBjKDAsIDAsIDIwMDAsIDIwMDApKQ0KDQpsZWdlbmQzZCgidG9wcmlnaHQiLCBsZWdlbmQgPSBncm91cHMsIHBjaCA9IDE2LCBjb2wgPSBjb2xzLCBpbnNldCA9IGMoMCksIGNleCA9IDUpDQoNCnJnbHdpZGdldCgpDQpgYGANCg0KIyBTdW1tYXJ5DQoNCkFkZGVkIDMgbmV3IGNvbGxlY3Rpb25zOg0KDQoxKSBDTUJBUkwxNyAtIEJhcmxpbmcgQmF5IENyZWVrIC0gOS8xLzIwMTcNCjIpIENNS0lBVjE3IC0gS2lhdmFrIFBvcnRhZ2UgLSA5LzEvMjAxNw0KMykgQ01OQVRBMTcgLSBOYXRhbGlhIEJheSBDcmVlayAtIDkvMS8yMDE3DQoNCk9mIG5vdGUsIHRoZSAyMDE3IGNvbGxlY3Rpb24gZnJvbSBCYXJsaW5nIEJheSBDcmVlayBjYW1lIGZyb20gaGlnaGVyIHVwIGluIHRoZSBkcmFpbmFhZ2UgKEJpcmNoIEZvc3RlciwgcGVyc29uYWwgY29tbXVuaWNhdGlvbiksIGJ1dCBzdGlsbCBsb29rcyB2ZXJ5IHNpbWlsYXIgdG8gdGhlIDIwMTUgU2VwdGVtYmVyIGNvbGxlY3Rpb24uIEtpYXZhayBQb3J0YWdlIGlzIGNsb3NlbHkgcmVsYXRlZCB0byBCYXJsaW5nLCBhbmQgTmF0YWxpYSB3YXMgYml0IGZ1cnRoZXIgYXdheSBmcm9tIHRoZSBtYWluIGNsdXN0ZXIuDQoNClRoaXMgdXBkYXRlIGRvZXMgbm90IGNoYW5nZSBhbnkgZGVwYXJ0bWVudGFsIHJlY29tbWVuZGF0aW9ucyByZWdhcmRpbmcgdGhlIHVzZSBvZiBsb2NhbCBicm9vZHNvdXJjZSAoQmFybGluZyBCYXkgQ3JlZWspIGZvciBhIGNodW0gaGF0Y2hlcnkgaW4gT2xkIEhhcmJvci4=